All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.dengchen2020.core.utils.SqlMetaUtils Maven / Gradle / Ivy

There is a newer version: 0.0.28
Show newest version
package io.github.dengchen2020.core.utils;

import jakarta.persistence.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ConcurrentReferenceHashMap;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ConcurrentMap;

/**
 * sql元数据解析工具类
 * @author dengchen
 * @since 2024/6/22
 */
public abstract class SqlMetaUtils {

    private static final Logger log = LoggerFactory.getLogger(SqlMetaUtils.class);

    private static final ConcurrentMap tableInfoCache = new ConcurrentReferenceHashMap<>();

    public static class TableInfo {

        private String tableName;

        private String schema = "";

        private List columns = new ArrayList<>();

        private String idColumn;

        private Method getIdMethod;

        private Method getVersionMethod;

        private Method prePersisit;

        private Method postPersisit;

        private Method preUpdate;

        private Method postUpdate;

        private Method preRemove;

        private Method postRemove;

        private Method postLoad;

        private String selectAllSql;

        public String getTableName() {
            return tableName;
        }

        public void setTableName(String tableName) {
            this.tableName = tableName;
        }

        public String getSchema() {
            return schema;
        }

        public void setSchema(String schema) {
            this.schema = schema;
        }

        public List getColumns() {
            return columns;
        }

        public void setColumns(List column) {
            this.columns = column;
        }

        public String getIdColumn() {
            return idColumn;
        }

        public void setIdColumn(String idColumn) {
            this.idColumn = idColumn;
        }

        public Method getGetIdMethod() {
            return getIdMethod;
        }

        public void setGetIdMethod(Method getIdMethod) {
            this.getIdMethod = getIdMethod;
        }

        public Method getGetVersionMethod() {
            return getVersionMethod;
        }

        public void setGetVersionMethod(Method getVersionMethod) {
            this.getVersionMethod = getVersionMethod;
        }

        public Method getPrePersisit() {
            return prePersisit;
        }

        public void setPrePersisit(Method prePersisit) {
            this.prePersisit = prePersisit;
        }

        public Method getPostPersisit() {
            return postPersisit;
        }

        public void setPostPersisit(Method postPersisit) {
            this.postPersisit = postPersisit;
        }

        public Method getPreUpdate() {
            return preUpdate;
        }

        public void setPreUpdate(Method preUpdate) {
            this.preUpdate = preUpdate;
        }

        public Method getPostUpdate() {
            return postUpdate;
        }

        public void setPostUpdate(Method postUpdate) {
            this.postUpdate = postUpdate;
        }

        public Method getPreRemove() {
            return preRemove;
        }

        public void setPreRemove(Method preRemove) {
            this.preRemove = preRemove;
        }

        public Method getPostRemove() {
            return postRemove;
        }

        public void setPostRemove(Method postRemove) {
            this.postRemove = postRemove;
        }

        public Method getPostLoad() {
            return postLoad;
        }

        public void setPostLoad(Method postLoad) {
            this.postLoad = postLoad;
        }

        public String getSelectAllSql() {
            return selectAllSql;
        }

        public void setSelectAllSql(String selectAllSql) {
            this.selectAllSql = selectAllSql;
        }
    }

    /**
     * 添加父类方法
     */
    public static void addSuperMethods(Class entityClass, List methods) {
        if (entityClass.getSuperclass() != null) {
            addSuperMethods(entityClass.getSuperclass(), methods);
        }
        if (entityClass.getAnnotation(MappedSuperclass.class) != null) {
            methods.addAll(new ArrayList<>(Arrays.asList(ReflectionUtils.getDeclaredMethods(entityClass))));
        }
    }

    /**
     * 添加父类字段
     */
    public static void addSuperFields(Class entityClass, List fields) {
        if (entityClass.getSuperclass() != null) {
            addSuperFields(entityClass.getSuperclass(), fields);
        }
        if (entityClass.getAnnotation(MappedSuperclass.class) != null) {
            fields.addAll(new ArrayList<>(Arrays.asList(entityClass.getDeclaredFields())));
        }
    }

    /**
     * 保存回调函数
     */
    private static void saveCallbackMethod(Method method, TableInfo tableInfo) {
        if (tableInfo.getPrePersisit() == null && method.getAnnotation(PrePersist.class) != null) {
            ReflectionUtils.makeAccessible(method);
            tableInfo.setPrePersisit(method);
        }
        if (tableInfo.getPostPersisit() == null && method.getAnnotation(PostPersist.class) != null) {
            ReflectionUtils.makeAccessible(method);
            tableInfo.setPostPersisit(method);
        }
        if (tableInfo.getPreUpdate() == null && method.getAnnotation(PreUpdate.class) != null) {
            ReflectionUtils.makeAccessible(method);
            tableInfo.setPreUpdate(method);
        }
        if (tableInfo.getPostUpdate() == null && method.getAnnotation(PostUpdate.class) != null) {
            ReflectionUtils.makeAccessible(method);
            tableInfo.setPostUpdate(method);
        }
        if (tableInfo.getPreRemove() == null && method.getAnnotation(PreRemove.class) != null) {
            ReflectionUtils.makeAccessible(method);
            tableInfo.setPreRemove(method);
        }
        if (tableInfo.getPostRemove() == null && method.getAnnotation(PostRemove.class) != null) {
            ReflectionUtils.makeAccessible(method);
            tableInfo.setPostRemove(method);
        }
        if (tableInfo.getPostLoad() == null && method.getAnnotation(PostLoad.class) != null) {
            ReflectionUtils.makeAccessible(method);
            tableInfo.setPostLoad(method);
        }
    }

    /**
     * 解析@Column指定的字段名
     *
     * @return 字段名
     */
    private static String getColumnName(Field field) {
        Column column = field.getAnnotation(Column.class);
        if (column == null || !StringUtils.hasText(column.name())) {
            return convertToSnakeCase(field.getName());
        }
        return column.name();
    }

    /**
     * 转化成蛇形下划线命名格式
     *
     * @param name 原字段名
     * @return 新字段名
     */
    public static String convertToSnakeCase(String name) {
        StringBuilder result = new StringBuilder();
        for (int i = 0,len = name.length(); i < len; i++) {
            char c = name.charAt(i);
            if (Character.isUpperCase(c) && i > 0) {
                result.append("_");
            }
            result.append(Character.toLowerCase(c));
        }
        return result.toString();
    }

    public static  TableInfo init(Class entityClass) {
        String entityName = entityClass.getName();
        return tableInfoCache.computeIfAbsent(entityName, key -> {
            TableInfo tableInfo = new TableInfo();
            Table table = entityClass.getAnnotation(Table.class);
            if (table == null) {
                tableInfo.setTableName(convertToSnakeCase(key));
            } else {
                tableInfo.setTableName(table.name());
                tableInfo.setSchema(table.schema());
            }
            List methods = new ArrayList<>();
            addSuperMethods(entityClass, methods);
            methods.addAll(new ArrayList<>(Arrays.asList(ReflectionUtils.getDeclaredMethods(entityClass))));
            List fields = new ArrayList<>();
            addSuperFields(entityClass, fields);
            fields.addAll(new ArrayList<>(Arrays.asList(entityClass.getDeclaredFields())));
            String idFieldName = null;
            String versionFieldName = null;
            for (Field field : fields) {
                if(!Modifier.isStatic(field.getModifiers()) && field.getAnnotation(Transient.class) == null){
                    tableInfo.getColumns().add(getColumnName(field));
                }
                if (idFieldName == null && field.getAnnotation(Id.class) != null) {
                    idFieldName = field.getName();
                    Column column = field.getAnnotation(Column.class);
                    if(column != null && StringUtils.hasText(column.name())){
                        tableInfo.setIdColumn(column.name());
                    }else {
                        tableInfo.setIdColumn(convertToSnakeCase(idFieldName));
                    }
                }
                if (versionFieldName == null && field.getAnnotation(Version.class) != null) {
                    versionFieldName = field.getName();
                }
            }
            tableInfo.setSelectAllSql(String.join(",",tableInfo.getColumns()));
            String getIdMethodName = getMethodName(idFieldName);
            String getVersionMethodName = getMethodName(versionFieldName);
            boolean getId = true;
            boolean getVersion = true;
            for (Method method : methods) {
                saveCallbackMethod(method, tableInfo);
                if (getId && getIdMethodName != null) {
                    if (method.getName().equals(getIdMethodName) && method.getParameterCount() == 0 && method.getReturnType() != Void.class) {
                        ReflectionUtils.makeAccessible(method);
                        getId = false;
                        tableInfo.setGetIdMethod(method);
                    }
                    if (getId) {
                        if (method.getName().equals(idFieldName) && method.getParameterCount() == 0 && method.getReturnType() != Void.class) {
                            ReflectionUtils.makeAccessible(method);
                            getId = false;
                            tableInfo.setGetIdMethod(method);
                        }
                    }
                }
                if (getVersion && getVersionMethodName != null) {
                    if (method.getName().equals(getVersionMethodName) && method.getParameterCount() == 0 && method.getReturnType() != Void.class) {
                        ReflectionUtils.makeAccessible(method);
                        getVersion = false;
                        tableInfo.setGetVersionMethod(method);
                    }
                    if (getVersion) {
                        if (method.getName().equals(versionFieldName) && method.getParameterCount() == 0 && method.getReturnType() != Void.class) {
                            ReflectionUtils.makeAccessible(method);
                            getVersion = false;
                            tableInfo.setGetVersionMethod(method);
                        }
                    }
                }
            }
            return tableInfo;
        });
    }

    private static String getMethodName(String fieldName) {
        if (fieldName != null) {
            if (fieldName.length() > 1) {
                return "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
            } else {
                return "get" + fieldName.toUpperCase();
            }
        }
        return null;
    }

    public static  boolean isNew(T entity) {
        String entityClassName = entity.getClass().getName();
        TableInfo tableInfo = tableInfoCache.get(entityClassName);
        Method getIdMethod = tableInfo.getGetIdMethod();
        Method getVersionMethod = tableInfo.getGetVersionMethod();
        if (getIdMethod != null) {
            return ReflectionUtils.invokeMethod(getIdMethod, entity) == null || (getVersionMethod != null && ReflectionUtils.invokeMethod(getVersionMethod, entity) == null);
        }
        return false;
    }

    public static  void onBeforeConvert(T entity) {
        String entityClassName = entity.getClass().getName();
        TableInfo tableInfo = tableInfoCache.get(entityClassName);
        if(tableInfo.getPrePersisit() == null && tableInfo.getPreUpdate() == null){
            return;
        }
        Method getIdMethod = tableInfo.getGetIdMethod();
        Method getVersionMethod = tableInfo.getGetVersionMethod();
        if (getIdMethod != null) {
            Object id = ReflectionUtils.invokeMethod(getIdMethod, entity);
            if (id != null && (getVersionMethod == null || ReflectionUtils.invokeMethod(getVersionMethod, entity) != null)) {
                Method preUpdate = tableInfo.getPreUpdate();
                if (preUpdate != null) {
                    if (log.isDebugEnabled())
                        log.debug("onBeforeConvert forward to {} @preUpdate method", entity.getClass().getName());
                    ReflectionUtils.invokeMethod(preUpdate, entity);
                }
            } else {
                Method prePersist = tableInfo.getPrePersisit();
                if (prePersist != null) {
                    if (log.isDebugEnabled())
                        log.debug("onBeforeConvert forward to {} @prePersist method", entity.getClass().getName());
                    ReflectionUtils.invokeMethod(prePersist, entity);
                }
            }
        }
    }

    public static  void onAfterConvert(T entity) {
        String entityClassName = entity.getClass().getName();
        TableInfo tableInfo = tableInfoCache.get(entityClassName);
        if(tableInfo.getPostPersisit() == null && tableInfo.getPostUpdate() == null){
            return;
        }
        Method getIdMethod = tableInfo.getGetIdMethod();
        Method getVersionMethod = tableInfo.getGetVersionMethod();
        if (getIdMethod != null) {
            Object id = ReflectionUtils.invokeMethod(getIdMethod, entity);
            if (id != null && (getVersionMethod == null || ReflectionUtils.invokeMethod(getVersionMethod, entity) != null)) {
                Method postUpdate = tableInfo.getPostUpdate();
                if (postUpdate != null) {
                    if (log.isDebugEnabled())
                        log.debug("onAfterConvert forward to {} @postUpdate method", entity.getClass().getName());
                    ReflectionUtils.invokeMethod(postUpdate, entity);
                }
            } else {
                Method postPersist = tableInfo.getPostPersisit();
                if (postPersist != null) {
                    if (log.isDebugEnabled())
                        log.debug("onAfterConvert forward to {} @postPersist method", entity.getClass().getName());
                    ReflectionUtils.invokeMethod(postPersist, entity);
                }
            }
        }
    }

    public static  void onBeforeDelete(T entity) {
        String entityClassName = entity.getClass().getName();
        TableInfo tableInfo = tableInfoCache.get(entityClassName);
        Method preRemove = tableInfo.getPreRemove();
        if (preRemove != null) {
            if (log.isDebugEnabled())
                log.debug("onBeforeDelete forward to {} @preRemove method", entity.getClass().getName());
            ReflectionUtils.invokeMethod(preRemove, entity);
        }
    }

    public static  void onAfterDelete(T entity) {
        String entityClassName = entity.getClass().getName();
        TableInfo tableInfo = tableInfoCache.get(entityClassName);
        Method postRemove = tableInfo.getPostRemove();
        if (postRemove != null) {
            if (log.isDebugEnabled())
                log.debug("onAfterDelete forward to {} @postRemove method", entity.getClass().getName());
            ReflectionUtils.invokeMethod(postRemove, entity);
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy