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

cn.org.atool.fluent.mybatis.base.IRefs Maven / Gradle / Ivy

package cn.org.atool.fluent.mybatis.base;

import cn.org.atool.fluent.mybatis.base.crud.IQuery;
import cn.org.atool.fluent.mybatis.base.crud.IUpdate;
import cn.org.atool.fluent.mybatis.base.entity.IEntityHelper;
import cn.org.atool.fluent.mybatis.base.mapper.IRichMapper;
import cn.org.atool.fluent.mybatis.mapper.EntityHelperFactory;
import cn.org.atool.fluent.mybatis.metadata.DbType;
import cn.org.atool.fluent.mybatis.spring.MapperFactory;
import lombok.Setter;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import static cn.org.atool.fluent.mybatis.mapper.FluentConst.*;
import static cn.org.atool.fluent.mybatis.utility.MybatisUtil.assertNotEmpty;
import static cn.org.atool.fluent.mybatis.utility.MybatisUtil.methodNameOfEntity;

/**
 * EntityRefQuery: Entity @RefMethod关联关系, 关联加载基类
 *
 * @author darui.wu
 */
@SuppressWarnings({"unused", "unchecked", "rawtypes"})
public abstract class IRefs {
    // Ref 文件生成的固定路径
    public static final String Fix_Package = "cn.org.atool.fluent.mybatis.refs";
    /**
     * 单例变量, 需要被Spring容器初始化时赋值
     */
    private static IRefs INSTANCE;

    @Setter
    private DbType defaultDbType;

    /**
     * 返回框架默认的数据库类型
     *
     * @return DbType
     */
    public DbType defaultDbType() {
        if (instance().defaultDbType == null) {
            throw new RuntimeException("please setDefaultDbType(dbType) first.");
        }
        return instance().defaultDbType;
    }

    public static IEntityHelper findEntityHelper(Class clazz) {
        return EntityHelperFactory.getInstance(clazz);
    }

    /**
     * 返回查询关联单例
     * 必须将子类配置到Spring容器中进行bean初始化
     *
     * @return IRefs
     */
    public static IRefs instance() {
        if (INSTANCE != null) {
            return INSTANCE;
        }
        synchronized (IRefs.class) {
            if (INSTANCE != null) {
                return INSTANCE;
            }
            try {
                Class klass = Class.forName(IRefs.Fix_Package + ".Refs");
                INSTANCE = (IRefs) klass.getDeclaredConstructor().newInstance();
                return INSTANCE;
            } catch (Exception e) {
                throw new RuntimeException("new Refs error:" + e.getMessage(), e);
            }
        }
    }

    protected static RuntimeException springNotInitException() {
        return new RuntimeException("The cn.org.atool.fluent.mybatis.spring.MapperFactory must be configured as spring bean.");
    }

    /**
     * 返回clazz实体对应的默认Query实例
     *
     * @param clazz Entity类类型
     * @return IQuery
     */
    public abstract IQuery defaultQuery(Class clazz);

    /**
     * 返回clazz实体对应的空Query实例
     *
     * @param clazz Entity类类型
     * @return IQuery
     */
    public abstract IQuery emptyQuery(Class clazz);

    /**
     * 返回clazz实体对应的默认Updater实例
     *
     * @param clazz Entity类类型
     * @return IUpdate
     */
    public abstract IUpdate defaultUpdater(Class clazz);

    /**
     * 返回clazz实体对应的空Updater实例
     *
     * @param clazz Entity类类型
     * @return IUpdate
     */
    public abstract IUpdate emptyUpdater(Class clazz);

    /**
     * 返回clazz属性field对应的数据库字段名称
     *
     * @param clazz Entity类类型
     * @param field entity属性名
     * @return 数据库字段名称
     */
    public abstract String findColumnByField(Class clazz, String field);

    /**
     * 返回clazz实体的主键字段
     *
     * @param clazz Entity类类型
     * @return 主键字段
     */
    public abstract String findPrimaryColumn(Class clazz);

    /**
     * 实现entityClass#methodName方法
     *
     * @param entityClass Entity class name
     * @param methodName  Entity @RefMethod方法
     * @param args        入参(第一个参数是entity)
     * @param          ignore
     * @return ignore
     */
    public  T invoke(Class entityClass, String methodName, Object[] args) {
        IEntity entity = (IEntity) args[0];
        String methodOfEntity = methodNameOfEntity(methodName, this.findFluentEntityClass(entityClass));
        switch (methodName) {
            case Rich_Entity_Save:
                mapper(entity).save(entity);
                return (T) entity;
            case Rich_Entity_UpdateById:
                mapper(entity).updateById(entity);
                return (T) entity;
            case Rich_Entity_FindById:
                IEntity result = mapper(entity).findById(entity.findPk());
                return (T) result;
            case Rich_Entity_DeleteById:
                mapper(entity).deleteById(entity.findPk());
                return null;
            case Rich_Entity_LogicDeleteById:
                mapper(entity).logicDeleteById(entity.findPk());
                return null;
            case RichEntity_ListByNotNull:
                Map where = entity.toColumnMap();
                assertNotEmpty("the property of entity can't be all empty.", where);
                List list = mapper(entity).listByMap(where);
                return (T) list;
            default:
                return this.invokeRefMethod(methodOfEntity, args);
        }
    }

    /**
     * 反射调用 methodOfEntity 方法
     *
     * @param methodOfEntity 方法名称
     * @param args           方法参数列表
     * @param             ignore
     * @return ignore
     */
    private  T invokeRefMethod(String methodOfEntity, Object[] args) {
        if (!refMethods.containsKey(methodOfEntity)) {
            throw new RuntimeException("the method[" + methodOfEntity + "] not defined or wrong define.");
        }
        Method method = refMethods.get(methodOfEntity);
        try {
            return (T) method.invoke(this, args);
        } catch (Exception e) {
            String err = String.format("invoke method[%s] error:%s", methodOfEntity, e.getMessage());
            throw new RuntimeException(err, e);
        }
    }

    private final Map refMethods = new ConcurrentHashMap<>(32);

    /**
     * 返回标注@FluentMybatis注解Entity类
     *
     * @param clazz 实例类
     * @return ignore
     */
    public Class findFluentEntityClass(Class clazz) {
        Set> all = this.allEntityClass();
        if (all.isEmpty()) {
            throw springNotInitException();
        }
        Class aClass = clazz;
        while (aClass != Object.class && aClass != RichEntity.class) {
            if (all.contains(aClass)) {
                return aClass;
            } else {
                aClass = aClass.getSuperclass();
            }
        }
        throw new RuntimeException("the class[" + clazz.getName() + "] is not a @FluentMybatis Entity.");
    }

    /**
     * 所有Entity Class
     *
     * @return ignore
     */
    protected abstract Set> allEntityClass();

    /**
     * 返回spring管理对应的mapper bean
     *
     * @param entity 数据库实体类实例
     * @return ignore
     */
    public static IRichMapper mapper(IEntity entity) {
        return IRefs.mapper(entity.getClass());
    }

    /**
     * 返回spring管理对应的mapper bean
     *
     * @param clazz 实体类
     * @return ignore
     */
    public static IRichMapper mapper(Class clazz) {
        return instance().getMapper(clazz);
    }

    protected abstract IRichMapper getMapper(Class clazz);

    /**
     * 从spring容器中获取Mapper
     */
    public void wiredMapper() {
        Method[] methods = this.getClass().getMethods();
        for (Method method : methods) {
            if (method.getParameterCount() == 0) {
                continue;
            }
            Class parameterType = method.getParameterTypes()[0];
            if (RichEntity.class.isAssignableFrom(parameterType)) {
                this.refMethods.put(method.getName(), method);
            }
        }
        this.initEntityMapper();
    }

    /**
     * 初始化 entity mapper
     */
    protected abstract void initEntityMapper();

    protected MapperFactory mapperFactory;

    protected Object relation;

    /**
     * 设置实体类的关联自定义实现
     *
     * @param relation 实体关联关系实现
     */
    public void setEntityRelation(Object relation, MapperFactory mapperFactory) {
        this.relation = relation;
        this.mapperFactory = mapperFactory;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy