package com.github.ltsopensource.core.support.bean; import com.github.ltsopensource.core.commons.utils.Assert; import com.github.ltsopensource.core.commons.utils.BeanUtils; import com.github.ltsopensource.core.commons.utils.ClassHelper; import com.github.ltsopensource.core.commons.utils.ReflectionUtils; import com.github.ltsopensource.core.compiler.AbstractCompiler; import com.github.ltsopensource.core.compiler.Compiler; import com.github.ltsopensource.core.exception.LtsRuntimeException; import com.github.ltsopensource.core.logger.Logger; import com.github.ltsopensource.core.logger.LoggerFactory; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicInteger; /** * @author Robert HG (254963746@qq.com) on 4/2/16. * 为了兼容javaassist 去掉泛型 */ public final class BeanCopierFactory { private static final Logger LOGGER = LoggerFactory.getLogger(BeanCopierFactory.class); private static Compiler COMPILER = AbstractCompiler.getCompiler(); private static final AtomicInteger SEQ = new AtomicInteger(0); private static final ConcurrentMap<Integer, Map<String, PropConverter<?, ?>>> SEQ_PROP_CVT_MAP = new ConcurrentHashMap<Integer, Map<String, PropConverter<?, ?>>>(); public static <Source, Target> BeanCopier<Source, Target> createCopier( Class<?> sourceClass, Class<?> targetClass) { return createCopier(sourceClass, targetClass, false, null); } public static <Source, Target> BeanCopier<Source, Target> createCopier( Class<?> sourceClass, Class<?> targetClass, boolean deepCopy) { return createCopier(sourceClass, targetClass, deepCopy, null); } public static <Source, Target> BeanCopier<Source, Target> createCopier( Class<?> sourceClass, Class<?> targetClass, Map<String, PropConverter<?, ?>> propCvtMap) { return createCopier(sourceClass, targetClass, false, propCvtMap); } @SuppressWarnings("unchecked") public static <Source, Target> BeanCopier<Source, Target> createCopier( Class<?> sourceClass, Class<?> targetClass, boolean deepCopy, Map<String, PropConverter<?, ?>> propCvtMap ) { Assert.notNull(sourceClass, "sourceClass can't be null"); Assert.notNull(targetClass, "targetClass can't be null"); Integer sequence = SEQ.incrementAndGet(); if (propCvtMap != null) { SEQ_PROP_CVT_MAP.putIfAbsent(sequence, propCvtMap); } try { Class<?> beanCopierClazz = COMPILER.compile(getClassCode(sequence, sourceClass, targetClass, deepCopy, propCvtMap)); final BeanCopierAdapter beanCopier = (BeanCopierAdapter) beanCopierClazz.newInstance(); return new BeanCopier<Source, Target>() { @Override public void copyProps(Source source, Target target) { beanCopier.copyProps(source, target); } }; } catch (Exception e) { throw new LtsRuntimeException("Generate BeanCopier error, sourceClass=" + sourceClass.getName() + ", targetClass=" + targetClass.getName(), e); } } /** * 生成BeanCopier的实现类源码 */ private static String getClassCode(Integer sequence, Class<?> sourceClass, Class<?> targetClass, boolean deepCopy, final Map<String, PropConverter<?, ?>> propCvtMap) throws Exception { JavaSourceBean javaSourceBean = new JavaSourceBean(); javaSourceBean.setPackageName(BeanCopierFactory.class.getPackage().getName()); javaSourceBean.addImport(BeanCopierAdapter.class.getName()); javaSourceBean.addImport(sourceClass.getName()); javaSourceBean.addImport(targetClass.getName()); javaSourceBean.addImport(PropConverter.class.getName()); String beanCopierClassName = sourceClass.getSimpleName() + "2" + targetClass.getSimpleName() + BeanCopier.class.getSimpleName() + sequence; String classDefinitionCode = "public class " + beanCopierClassName + " extends " + BeanCopierAdapter.class.getName(); javaSourceBean.setClassDefinition(classDefinitionCode); javaSourceBean.addMethod(getMethodImplCode(sequence, sourceClass, targetClass, deepCopy, propCvtMap)); if (LOGGER.isDebugEnabled()) { LOGGER.debug(javaSourceBean.toString()); } return javaSourceBean.toString(); } /** * 构建方法体实现 */ private static String getMethodImplCode(Integer sequence, Class<?> sourceClass, Class<?> targetClass, boolean deepCopy, final Map<String, PropConverter<?, ?>> propCvtMap) throws Exception { StringBuilder methodCode = new StringBuilder(); methodCode.append("public void copyProps(").append(Object.class.getName()).append(" sourceObj, ").append(Object.class.getName()).append(" targetObj){\n"); methodCode.append(sourceClass.getName()).append(" source = ").append("(").append(sourceClass.getName()).append(")sourceObj;\n"); methodCode.append(targetClass.getName()).append(" target = ").append("(").append(targetClass.getName()).append(")targetObj;\n"); // 这里查找了包括父类的属性 Field[] targetFields = ReflectionUtils.findFields(targetClass); for (Field field : targetFields) { if (!Modifier.isStatic(field.getModifiers())) { // 是否含有set方法 String methodNameSuffix = capitalize(field.getName()); Class<?> targetFieldClass = field.getType(); Method setMethod = ReflectionUtils.findMethod(targetClass, "set" + methodNameSuffix, targetFieldClass); if (setMethod == null) { setMethod = ReflectionUtils.findMethod(targetClass, "set" + field.getName(), targetFieldClass); if (setMethod != null) { methodNameSuffix = field.getName(); } } if (setMethod != null) { // 查看这个属性是否有 PropConverter if (propCvtMap != null && propCvtMap.containsKey(field.getName())) { String converterName = field.getName() + "Converter"; String converterType = PropConverter.class.getName(); methodCode.append(converterType).append(" ").append(converterName).append(" = (").append(converterType).append(")") .append(BeanCopierFactory.class.getName()).append(".getConverter(").append(sequence).append(",").append("\"").append(field.getName()).append("\");\n"); methodCode.append("target.").append(setMethod.getName()).append("(") .append("(").append(targetFieldClass.getName()).append(")").append(converterName).append(".convert(").append("source").append(")") .append(");\n"); continue; } // set方法存在,看是否 sourceClass 有get方法或者is方法 Method getMethod = ReflectionUtils.findMethod(sourceClass, "get" + methodNameSuffix); if (getMethod == null && (targetFieldClass == boolean.class || targetFieldClass == Boolean.class)) { getMethod = ReflectionUtils.findMethod(sourceClass, "is" + methodNameSuffix); } if (getMethod == null) { continue; } // 查看返回值是否相同,不完全相同是否可以转换 if (getMethod.getReturnType() == targetFieldClass) { if (!deepCopy) { methodCode.append("target.").append(setMethod.getName()).append("(").append("source.").append(getMethod.getName()).append("()").append(");\n"); } else { if (ClassHelper.isPrimitiveType(targetFieldClass) || ClassHelper.isPrimitiveWrapperType(targetFieldClass) || targetFieldClass == String.class) { methodCode.append("target.").append(setMethod.getName()).append("(").append("source.").append(getMethod.getName()).append("()").append(");\n"); } else { // 深度复制,对于非基本类型的采用流的方式拷贝 methodCode.append("target.").append(setMethod.getName()).append("(") .append("(").append(targetFieldClass.getName()).append(")") .append(BeanUtils.class.getName()).append(".deepClone(") .append("source.").append(getMethod.getName()).append("()") .append(")") .append(");\n"); } } } else if (ClassHelper.isPrimitiveType(targetFieldClass) && ClassHelper.getPrimitiveTypeByWrapper(getMethod.getReturnType()) == targetFieldClass) { // 类似 target.setInt(source.getInt() == null ? 0 : source.getInt()); methodCode.append("target.").append(setMethod.getName()).append("("); methodCode.append("source.").append(getMethod.getName()).append("() == null ? ").append(String.valueOf(ClassHelper.getPrimitiveDftValue(targetFieldClass))).append(" : ").append("source.").append(getMethod.getName()).append("()"); methodCode.append(");\n"); } else if (ClassHelper.isPrimitiveWrapperType(targetFieldClass) && ClassHelper.getWrapperTypeByPrimitive(getMethod.getReturnType()) == targetFieldClass) { methodCode.append("target.").append(setMethod.getName()).append("(").append("source.").append(getMethod.getName()).append("()").append(");\n"); } } } } methodCode.append("}"); return methodCode.toString(); } private static String capitalize(String str) { return String.valueOf(Character.toTitleCase(str.charAt(0))) + str.substring(1); } /** * 会被动态类使用 */ public static PropConverter<?, ?> getConverter(int sequence, String propName) { Map<String, PropConverter<?, ?>> map = SEQ_PROP_CVT_MAP.get(sequence); return map.get(propName); } }