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;
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");
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;
}
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());
}
}
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);
}
}
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);
}
}
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);
}
}
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);
}
}
static BaseDao getMapperBean(String className) {
String mapperClassName = className + "Mapper";
return SpringContextUtil.getBean(LogicStringUtil.lowerCaseFirstLetter(mapperClassName));
}
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());
}
}