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

com.github.freegeese.easymybatis.meta.MetaEntityClass Maven / Gradle / Ivy

The newest version!
package com.github.freegeese.easymybatis.meta;

import com.github.freegeese.easymybatis.EasyMybatisConfiguration;
import com.github.freegeese.easymybatis.annotation.*;
import com.github.freegeese.easymybatis.util.RefUtils;
import lombok.Data;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeException;
import org.apache.ibatis.type.TypeHandler;
import org.apache.ibatis.type.UnknownTypeHandler;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 实体类元数据信息
 *
 * @author zhangguangyong
 * @since 1.0
 */
@Data
public class MetaEntityClass {
    /**
     * get方法
     */
    private List getMethods;
    /**
     * get方法对应的字段
     */
    private List getFields;
    /**
     * 实体对应的结果集
     */
    private List resultMappings;
    /**
     * 实体对应的表名
     */
    private String table;
    /**
     * 层级结构get方法
     */
    private static final TreeableGetMethod treeableGetMethod = new TreeableGetMethod();

    @Data
    public static class TreeableGetMethod {
        private String getId = "getId";
        private String getParentId = "getParentId";
        private String getPath = "getPath";
        private String getSort = "getSort";
    }

    /**
     * 列映射信息
     */
    @Data
    public static class ResultMapping {
        /**
         * 属性
         */
        private String property;
        /**
         * 列
         */
        private String column;
        /**
         * 属性类型
         */
        private Class javaType;
        /**
         * 列类型
         */
        private JdbcType jdbcType;
        /**
         * 类型转换处理
         */
        private TypeHandler typeHandler;
        /**
         * 是否为主键
         */
        private boolean primaryKey;
        /**
         * 是否为自增列
         */
        private boolean auto;
        /**
         * get方法
         */
        private Method getMethod;

        public String ne(String prefix) {
            return sql(Condition.ne, prefix);
        }

        public String ne() {
            return sql(Condition.ne);
        }

        public String eq(String prefix) {
            return sql(Condition.eq, prefix);
        }

        public String eq() {
            return sql(Condition.eq);
        }

        public String gt(String prefix) {
            return sql(Condition.gt, prefix);
        }

        public String gt() {
            return sql(Condition.gt);
        }

        public String lt(String prefix) {
            return sql(Condition.lt, prefix);
        }

        public String lt() {
            return sql(Condition.lt);
        }

        public String ge(String prefix) {
            return sql(Condition.ge, prefix);
        }

        public String ge() {
            return sql(Condition.ge);
        }

        public String le(String prefix) {
            return sql(Condition.le, prefix);
        }

        public String le() {
            return sql(Condition.le);
        }

        private String sql(Condition condition, String prefix) {
            return String.join(" ", column, condition.symbol, "#{", prefix + "." + property, "}");
        }

        private String sql(Condition condition) {
            return String.join(" ", column, condition.symbol, "#{" + property + "}");
        }

        enum Condition {
            ne("!="),
            eq("="),
            gt(">"),
            lt("<"),
            ge(">="),
            le("<=");
            private final String symbol;

            Condition(String symbol) {
                this.symbol = symbol;
            }
        }

    }

    public static TreeableGetMethod getTreeableGetMethod() {
        return treeableGetMethod;
    }

    /**
     * 获取实体元数据
     *
     * @param clazz
     * @return
     */
    public static MetaEntityClass forClass(Class clazz) {
        EasyMybatisConfiguration cfg = EasyMybatisConfiguration.getInstance();
        Function, String> entityClassToTable = cfg.getEntityClassToTable();
        Function entityGetMethodToColumn = cfg.getEntityGetMethodToColumn();

        MetaEntityClass meta = new MetaEntityClass();

        // 表名
        meta.setTable(entityClassToTable.apply(clazz));

        // getMethods
        List getMethods = RefUtils.getAllDeclaredMethods(clazz).stream().filter(v -> v.getName().startsWith("get") && Objects.isNull(v.getAnnotation(Ignore.class))).collect(Collectors.toList());
        Map getMethodMap = getMethods.stream().collect(Collectors.toMap(MetaEntityClass::toProperty, Function.identity()));

        // fields
        List fields = RefUtils.getAllDeclaredFields(clazz).stream().filter(v -> Objects.isNull(v.getAnnotation(Ignore.class))).collect(Collectors.toList());

        List resultMappings = new ArrayList<>();
        for (Field field : fields) {
            String property = field.getName();
            if (!getMethodMap.containsKey(property)) {
                continue;
            }
            Method getMethod = getMethodMap.get(property);

            ResultMapping resultMapping = new ResultMapping();
            resultMapping.setGetMethod(getMethod);
            resultMapping.setProperty(property);
            resultMapping.setJavaType(getMethod.getReturnType());

            // column
            Column column = getMethod.getAnnotation(Column.class);
            column = Objects.isNull(column) ? field.getAnnotation(Column.class) : column;
            if (Objects.nonNull(column)) {
                JdbcType jdbcType = column.jdbcType();
                if (jdbcType != JdbcType.UNDEFINED) {
                    resultMapping.setJdbcType(jdbcType);
                }

                Class> typeHandler = column.typeHandler();
                if (typeHandler != UnknownTypeHandler.class) {
                    resultMapping.setTypeHandler(getInstance(resultMapping.getJavaType(), typeHandler));
                }
            }
            // 列名
            resultMapping.setColumn(Objects.isNull(column) || column.value().isEmpty() ? entityGetMethodToColumn.apply(getMethod) : column.value());

            // primaryKey
            resultMapping.setPrimaryKey(Objects.nonNull(getMethod.getAnnotation(Id.class)) || Objects.nonNull(field.getAnnotation(Id.class)));
            GeneratedValue generatedValue = getMethod.getAnnotation(GeneratedValue.class);
            generatedValue = Objects.isNull(generatedValue) ? field.getAnnotation(GeneratedValue.class) : generatedValue;
            resultMapping.setAuto(Objects.nonNull(generatedValue) && generatedValue.strategy() == GenerationType.AUTO);

            resultMappings.add(resultMapping);
        }

        meta.setGetMethods(getMethods);
        meta.setGetFields(fields.stream().filter(v -> getMethodMap.containsKey(v.getName())).collect(Collectors.toList()));
        meta.setResultMappings(resultMappings);

        return meta;
    }

    /**
     * 获取所有列名
     *
     * @return
     */
    public String getColumns() {
        return resultMappings.stream().map(MetaEntityClass.ResultMapping::getColumn).collect(Collectors.joining(","));
    }

    /**
     * 获取主键列
     *
     * @return
     */
    public ResultMapping getPrimaryKeyResultMapping() {
        return resultMappings.stream().filter(ResultMapping::isPrimaryKey).findFirst().orElse(null);
    }

    /**
     * 获取 auto 之外的所有列
     *
     * @return
     */
    public List getResultMappingsWithoutAuto() {
        return resultMappings.stream().filter(v -> !v.isAuto()).collect(Collectors.toList());
    }

    /**
     * 获取 auto 列
     *
     * @return
     */
    public List getAutoResultMappings() {
        return resultMappings.stream().filter(ResultMapping::isAuto).collect(Collectors.toList());
    }

    /**
     * 获取所有非空列
     *
     * @param target
     * @return
     */
    public List getResultMappingsWithoutNull(Object target) {
        return resultMappings.stream().filter(v -> Objects.nonNull(RefUtils.invokeMethod(v.getGetMethod(), target))).collect(Collectors.toList());
    }

    /**
     * 获取所有非(auto 且 null) 列
     *
     * @param target
     * @return
     */
    public List getResultMappingsWithoutAutoAndNull(Object target) {
        return resultMappings.stream().filter(v -> !(v.isAuto() && Objects.isNull(RefUtils.invokeMethod(v.getGetMethod(), target)))).collect(Collectors.toList());
    }

    /**
     * 获取所有非 (primaryKey 或 null) 列
     *
     * @param target
     * @return
     */
    public List getResultMappingsWithoutPrimaryKeyOrNull(Object target) {
        return resultMappings.stream().filter(v -> !(v.isPrimaryKey() || Objects.isNull(RefUtils.invokeMethod(v.getGetMethod(), target)))).collect(Collectors.toList());
    }

    public ResultMapping checkPrimaryKey(Object target) {
        Optional primaryKeyOptional = resultMappings.stream().filter(MetaEntityClass.ResultMapping::isPrimaryKey).findFirst();
        if (!primaryKeyOptional.isPresent()) {
            throw new RuntimeException("主键字段不存在[" + target.getClass() + "]");
        }
        ResultMapping primaryKeyResultMapping = primaryKeyOptional.get();
        if (Objects.isNull(RefUtils.invokeMethod(primaryKeyResultMapping.getGetMethod(), target))) {
            throw new RuntimeException("主键字段值为空[" + primaryKeyResultMapping.getProperty() + ", " + target.getClass() + "]");
        }
        return primaryKeyResultMapping;
    }

    public Map getGetMethodAndThisMap() {
        return resultMappings.stream().collect(Collectors.toMap(v -> v.getGetMethod().getName(), Function.identity()));
    }

    /**
     * 将 get 方法名称转换属性名称
     *
     * @param getMethod
     * @return
     */
    private static String toProperty(Method getMethod) {
        String name = getMethod.getName().substring(3);
        return name.substring(0, 1).toLowerCase() + name.substring(1);
    }

    /**
     * 反射构造 typeHandler 来自Mybatis源码
     *
     * @param javaTypeClass
     * @param typeHandlerClass
     * @param 
     * @return
     */
    private static  TypeHandler getInstance(Class javaTypeClass, Class typeHandlerClass) {
        if (javaTypeClass != null) {
            try {
                Constructor c = typeHandlerClass.getConstructor(Class.class);
                return (TypeHandler) c.newInstance(javaTypeClass);
            } catch (NoSuchMethodException ignored) {
                // ignored
            } catch (Exception e) {
                throw new TypeException("Failed invoking constructor for handler " + typeHandlerClass, e);
            }
        }
        try {
            Constructor c = typeHandlerClass.getConstructor();
            return (TypeHandler) c.newInstance();
        } catch (Exception e) {
            throw new TypeException("Unable to find a usable constructor for " + typeHandlerClass, e);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy