DomainConverter领域对象转换

165 阅读2分钟
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

import com.alibaba.yiupin.marketing.api.enums.MarketingErrorCode;
import com.alibaba.yiupin.marketing.api.exception.DistMarketingBackBizException;
import com.alibaba.yiupin.marketing.domain.converter.annotation.DomainObject;
import com.alibaba.yiupin.marketing.domain.entity.IEnitity;
import com.alibaba.yiupin.marketing.domain.repository.AbstractRepository;
import com.alibaba.yiupin.marketing.infrastructure.common.utils.LogicStringUtil;
import com.alibaba.yiupin.marketing.infrastructure.constant.LogConstant;
import com.alibaba.yiupin.marketing.infrastructure.dao.rds.doobject.DataObject;
import com.alibaba.yiupin.marketing.infrastructure.dao.rds.mapper.BaseDao;

import com.common.collect.container.SpringContextUtil;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;

/**
 * 领域对象转换
 *
 * @author: wujin
 * @date: 2021-02-24
 */
public class DomainConverter {
    private static final String APP_INFRASTRUCTURE_DO_PREFIX
        = "com.alibaba.yiupin.marketing.infrastructure.dao.rds.doobject.";
    private static final String APP_INFRASTRUCTURE_MAPPER_PREFIX
        = "com.alibaba.yiupin.marketing.infrastructure.dao.rds.mapper.";
    private static final String APP_DOMAIN_ENTITY_PREFIX = "com.alibaba.yiupin.marketing.domain.entity.";
    private static final String APP_DOMAIN_REPOSITORY_PREFIX = "com.alibaba.yiupin.marketing.domain.repository.";

    private final static List<String> ignoreFields = Arrays.asList("serialVersionUID");

    /**
     * DO转换成Entity
     * @param dataObject 数据库对象
     * @param <D> 数据库对象
     * @param <E> 实体类
     * @return
     */
    public static <D extends DataObject, E extends IEnitity> E convert(D dataObject) {
        if (dataObject == null) {
            return null;
        }
        Field[] doFields = FieldUtils.getAllFields(dataObject.getClass());
        String doClassName = dataObject.getClass().getSimpleName();
        Class<E> entityClass = null;
        E entity = null;
        Field[] entityFields = FieldUtils.getAllFields(dataObject.getClass());
        try {
            entityClass = (Class<E>)getEntityClass(doClassName.substring(0, doClassName.length() - 2));
            entity = entityClass.newInstance();
            entityFields = FieldUtils.getAllFields(entityClass);
        } catch (Exception e) {
            LogConstant.runLog.warn("DomainConverter.getEntityClass error , doClassName = {}, errorMessage = {}",
                doClassName, e.getMessage());
        }
        if (doFields != null && doFields.length >= 1 && entity != null) {

            List<Field> domainFieldList = Arrays.stream(entityFields).filter(
                (field) -> isDomainObject(field)).collect(Collectors.toList());
            Map<String, Field> domainObjectMap = domainFieldList.stream().collect(
                Collectors.toMap(field -> getDomainAnnoatationByField(field).associationField(), Function.identity()));
            for (Field doField : doFields) {
                if (ignoreFields.contains(doField.getName())) {
                    continue;
                }
                Field entityField = domainObjectMap.get(doField.getName());
                if (entityField != null) {
                    String entityFieldName = entityField.getName();
                    Class<E> fieldType = (Class<E>)entityField.getType();
                    Long associationId = (Long)getPropertyValue(doField.getName(), dataObject);
                    IEnitity associationEntity = getRepositoryBean(fieldType.getSimpleName()).findById(associationId);
                    setPropertyValue(entityFieldName, entity, associationEntity);
                }

                copyProperty(doField.getName(), dataObject, entity);

            }
        }
        return entity;
    }

    public static <D extends DataObject, E extends IEnitity> D convert(E entity) {
        if (entity == null) {
            return null;
        }
        Field[] entityFields = FieldUtils.getAllFields(entity.getClass());
        String entityClassName = entity.getClass().getSimpleName();
        Class<D> dataObjectClass = null;
        D dataObject = null;
        try {
            dataObjectClass = (Class<D>)getDOClass(entityClassName);
            dataObject = dataObjectClass.newInstance();
        } catch (Exception e) {
            LogConstant.runLog.warn("DomainConverter.getDOClass error , entityClassName = {}, errorMessage = {}",
                entityClassName, e.getMessage());
        }
        if (entityFields != null && entityFields.length > 0 && dataObject != null) {
            for (Field entityField : entityFields) {
                if (ignoreFields.contains(entityField.getName())) {
                    continue;
                }
                DomainObject annotation = entityField.getAnnotation(DomainObject.class);
                if (annotation != null) {
                    String associationField = annotation.associationField();
                    Object id = getPropertyValue("id", entity);
                    setPropertyValue(associationField, dataObject, id);
                } else {
                    copyProperty(entityField.getName(), entity, dataObject);
                }
            }
        }
        return dataObject;
    }

    public static <D extends DataObject, E extends IEnitity> List<D> convert2DoList(List<E> entityList) {
        if (CollectionUtils.isEmpty(entityList)) {
            return null;
        }
        List<D> dataObjectList = Lists.newArrayList();
        entityList.stream().forEach(e -> {
            dataObjectList.add(convert(e));
        });
        return dataObjectList;
    }

    public static <D extends DataObject, E extends IEnitity> List<E> convert2EntityList(List<D> dataObjectList) {
        if (CollectionUtils.isEmpty(dataObjectList)) {
            return null;
        }
        List<E> entityList = Lists.newArrayList();
        dataObjectList.stream().forEach(dataObject -> {
            entityList.add(convert(dataObject));
        });
        return entityList;
    }

    /**
     * 判断是否包含{@link DomainObject}
     *
     * @param field
     * @return
     */
    static boolean isDomainObject(Field field) {
        DomainObject[] domainFields = (DomainObject[])field.getAnnotationsByType(DomainObject.class);
        return domainFields != null && domainFields.length > 0;
    }

    static DomainObject getDomainAnnoatationByField(Field field) {
        DomainObject[] domainFields = (DomainObject[])field.getAnnotationsByType(DomainObject.class);
        return domainFields != null && domainFields.length > 0 ? domainFields[0] : null;
    }

    static void copyProperty(String property, Object source, Object target) {
        try {
            PropertyDescriptor sourcePd = new PropertyDescriptor(property, source.getClass());
            PropertyDescriptor targetPd = new PropertyDescriptor(property, target.getClass());
            if (targetPd != null && sourcePd != null) {
                Method readMethod = sourcePd.getReadMethod();
                Method writeMethod = targetPd.getWriteMethod();
                if (readMethod != null && writeMethod != null && ClassUtils.isAssignable(
                    writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {
                    if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
                        readMethod.setAccessible(true);
                    }

                    Object value = readMethod.invoke(source);
                    if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
                        writeMethod.setAccessible(true);
                    }

                    writeMethod.invoke(target, value);
                }
            }
        } catch (Exception e) {
            LogConstant.runLog.warn("DomainConverter.copyProperty error , fieldName = {}",
                property,e);
        }
    }

    static Object getPropertyValue(String property, Object obj) {
        try {
            PropertyDescriptor propertyDescriptor = new PropertyDescriptor(property, obj.getClass());
            Method readMethod = propertyDescriptor.getReadMethod();
            return readMethod.invoke(obj);
        } catch (Exception e) {
            LogConstant.runLog.warn("DomainConverter.getPropertyValue error , fieldName = {}",
                property);
        }
        return null;
    }

    static void setPropertyValue(String property, Object obj, Object value) {
        try {
            PropertyDescriptor propertyDescriptor = new PropertyDescriptor(property, obj.getClass());
            Method writeMethod = propertyDescriptor.getWriteMethod();
            writeMethod.invoke(obj, value);
        } catch (Exception e) {
            LogConstant.runLog.warn("DomainConverter.setPropertyValue error , fieldName = {}, errorMessage = {}",
                property, e.getMessage());
        }
    }

    /**
     * 获取DOClass
     *
     * @param className
     * @return
     * @throws ClassNotFoundException
     */
    static Class<?> getDOClass(String className) throws ClassNotFoundException {
        if (StringUtils.isBlank(className)) {
            throw new NullPointerException("param is null");
        } else {
            String fullPath = APP_INFRASTRUCTURE_DO_PREFIX + className + "DO";
            return Class.forName(fullPath);
        }
    }

    /**
     * 获取Entity
     *
     * @param className
     * @return
     * @throws ClassNotFoundException
     */
    static Class<?> getEntityClass(String className) throws ClassNotFoundException {
        if (StringUtils.isBlank(className)) {
            throw new NullPointerException("param is null");
        } else {
            String fullPath = APP_DOMAIN_ENTITY_PREFIX + className;
            return Class.forName(fullPath);
        }
    }

    /**
     * 获取对应的Repository
     *
     * @param className
     * @return
     * @throws ClassNotFoundException
     */
    static Class<?> getRepositoryClass(String className) throws ClassNotFoundException {
        if (StringUtils.isBlank(className)) {
            throw new NullPointerException("param is null");
        } else {
            String fullPath = APP_DOMAIN_REPOSITORY_PREFIX + className + "Repository";
            return Class.forName(fullPath);
        }
    }

    /**
     * 获取对应的Mapper
     *
     * @param className
     * @return
     * @throws ClassNotFoundException
     */
    static Class<?> getMapperClass(String className) throws ClassNotFoundException {
        if (StringUtils.isBlank(className)) {
            throw new NullPointerException("param is null");
        } else {
            String fullPath = APP_INFRASTRUCTURE_MAPPER_PREFIX + className + "Mapper";
            return Class.forName(fullPath);
        }
    }

    /**
     * 获取MapperBean
     *
     * @param className
     * @return
     */
    static BaseDao getMapperBean(String className) {
        String mapperClassName = className + "Mapper";
        return SpringContextUtil.getBean(LogicStringUtil.lowerCaseFirstLetter(mapperClassName));
    }

    /**
     * 获取RepositoryBean
     *
     * @param className
     * @return
     */
    static AbstractRepository getRepositoryBean(String className) {
        String repositoryClassName = className + "Repository";
        return SpringContextUtil.getBean(LogicStringUtil.lowerCaseFirstLetter(repositoryClassName));
    }

    public static void main(String[] args) throws ClassNotFoundException {
        System.out.println(getRepositoryClass("Campaign").getSimpleName());
        System.out.println(getMapperClass("Campaign").getSimpleName());
        System.out.println(getDOClass("Campaign").getSimpleName());
        System.out.println(getEntityClass("Campaign").getSimpleName());
    }
}