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

org.macrocloud.kernel.toolkit.beans.BeanCopier Maven / Gradle / Ivy

There is a newer version: 1.1.0-RELEASE
Show newest version

package org.macrocloud.kernel.toolkit.beans;


import org.macrocloud.kernel.toolkit.utils.BeanUtil;
import org.macrocloud.kernel.toolkit.utils.ClassUtil;
import org.macrocloud.kernel.toolkit.utils.ReflectUtil;
import org.macrocloud.kernel.toolkit.utils.StringUtil;
import org.springframework.asm.ClassVisitor;
import org.springframework.asm.Label;
import org.springframework.asm.Opcodes;
import org.springframework.asm.Type;
import org.springframework.cglib.core.*;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.security.ProtectionDomain;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;



/**
 * spring cglib 魔改
 *
 * 

* 1. 支持链式 bean,支持 map * 2. ClassLoader 跟 target 保持一致 *

* * @author macro */ public abstract class BeanCopier { /** The Constant CONVERTER. */ private static final Type CONVERTER = TypeUtils.parseType("org.springframework.cglib.core.Converter"); /** The Constant BEAN_COPIER. */ private static final Type BEAN_COPIER = TypeUtils.parseType(BeanCopier.class.getName()); /** The Constant BEAN_MAP. */ private static final Type BEAN_MAP = TypeUtils.parseType(Map.class.getName()); /** The Constant COPY. */ private static final Signature COPY = new Signature("copy", Type.VOID_TYPE, new Type[]{Constants.TYPE_OBJECT, Constants.TYPE_OBJECT, CONVERTER}); /** The Constant CONVERT. */ private static final Signature CONVERT = TypeUtils.parseSignature("Object convert(Object, Class, Object)"); /** The Constant BEAN_MAP_GET. */ private static final Signature BEAN_MAP_GET = TypeUtils.parseSignature("Object get(Object)"); /** The Constant CLASS_UTILS. */ private static final Type CLASS_UTILS = TypeUtils.parseType(ClassUtils.class.getName()); /** The Constant IS_ASSIGNABLE_VALUE. */ private static final Signature IS_ASSIGNABLE_VALUE = TypeUtils.parseSignature("boolean isAssignableValue(Class, Object)"); /** * The map to store {@link BeanCopier} of source type and class type for copy. */ private static final ConcurrentMap BEAN_COPIER_MAP = new ConcurrentHashMap<>(); /** * Creates the. * * @param source the source * @param target the target * @param useConverter the use converter * @return BeanCopier the bean copier */ public static BeanCopier create(Class source, Class target, boolean useConverter) { return BeanCopier.create(source, target, useConverter, false); } /** * Creates the. * * @param source the source * @param target the target * @param useConverter the use converter * @param nonNull the non null * @return BeanCopier the bean copier */ public static BeanCopier create(Class source, Class target, boolean useConverter, boolean nonNull) { BeanCopierKey copierKey = new BeanCopierKey(source, target, useConverter, nonNull); // 利用 ConcurrentMap 缓存 提高性能,接近 直接 get set return BEAN_COPIER_MAP.computeIfAbsent(copierKey, key -> { Generator gen = new Generator(); gen.setSource(key.getSource()); gen.setTarget(key.getTarget()); gen.setUseConverter(key.isUseConverter()); gen.setNonNull(key.isNonNull()); return gen.create(key); }); } /** * Bean copy. * * @param from from Bean * @param to to Bean * @param converter Converter */ abstract public void copy(Object from, Object to, @Nullable Converter converter); /** * The Class Generator. */ public static class Generator extends AbstractClassGenerator { /** The Constant SOURCE. */ private static final Source SOURCE = new Source(BeanCopier.class.getName()); /** The source. */ private Class source; /** The target. */ private Class target; /** The use converter. */ private boolean useConverter; /** The non null. */ private boolean nonNull; /** * Instantiates a new generator. */ Generator() { super(SOURCE); } /** * Sets the source. * * @param source the new source */ public void setSource(Class source) { if (!Modifier.isPublic(source.getModifiers())) { setNamePrefix(source.getName()); } this.source = source; } /** * Sets the target. * * @param target the new target */ public void setTarget(Class target) { if (!Modifier.isPublic(target.getModifiers())) { setNamePrefix(target.getName()); } this.target = target; } /** * Sets the use converter. * * @param useConverter the new use converter */ public void setUseConverter(boolean useConverter) { this.useConverter = useConverter; } /** * Sets the non null. * * @param nonNull the new non null */ public void setNonNull(boolean nonNull) { this.nonNull = nonNull; } /** *

Title: getDefaultClassLoader

*

Description:

. * * @return ClassLoader the default class loader * @see org.springframework.cglib.core.AbstractClassGenerator#getDefaultClassLoader() */ @Override protected ClassLoader getDefaultClassLoader() { // macro 保证 和 返回使用同一个 ClassLoader return target.getClassLoader(); } /** *

Title: getProtectionDomain

*

Description:

. * * @return ProtectionDomain the protection domain * @see org.springframework.cglib.core.AbstractClassGenerator#getProtectionDomain() */ @Override protected ProtectionDomain getProtectionDomain() { return ReflectUtils.getProtectionDomain(source); } /** *

Title: create

*

Description:

. * * @param key the key * @return BeanCopier the bean copier * @see org.springframework.cglib.core.AbstractClassGenerator#create(java.lang.Object) */ @Override public BeanCopier create(Object key) { return (BeanCopier) super.create(key); } /** *

Title: generateClass

*

Description:

. * * @param v the v * @see org.springframework.cglib.core.ClassGenerator#generateClass(org.springframework.asm.ClassVisitor) */ @Override public void generateClass(ClassVisitor v) { Type sourceType = Type.getType(source); Type targetType = Type.getType(target); ClassEmitter ce = new ClassEmitter(v); ce.begin_class(Constants.V1_2, Constants.ACC_PUBLIC, getClassName(), BEAN_COPIER, null, Constants.SOURCE_FILE); EmitUtils.null_constructor(ce); CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, COPY, null); // map 单独处理 if (Map.class.isAssignableFrom(source)) { generateClassFormMap(ce, e, sourceType, targetType); return; } // 2018.12.27 by macro 支持链式 bean // 注意:此处需兼容链式bean 使用了 spring 的方法,比较耗时 PropertyDescriptor[] getters = ReflectUtil.getBeanGetters(source); PropertyDescriptor[] setters = ReflectUtil.getBeanSetters(target); Map names = new HashMap<>(16); for (PropertyDescriptor getter : getters) { names.put(getter.getName(), getter); } Local targetLocal = e.make_local(); Local sourceLocal = e.make_local(); e.load_arg(1); e.checkcast(targetType); e.store_local(targetLocal); e.load_arg(0); e.checkcast(sourceType); e.store_local(sourceLocal); for (PropertyDescriptor setter : setters) { String propName = setter.getName(); CopyProperty targetIgnoreCopy = ReflectUtil.getAnnotation(target, propName, CopyProperty.class); // set 上有忽略的 注解 if (targetIgnoreCopy != null) { if (targetIgnoreCopy.ignore()) { continue; } // 注解上的别名,如果别名不为空,使用别名 String aliasTargetPropName = targetIgnoreCopy.value(); if (StringUtil.isNotBlank(aliasTargetPropName)) { propName = aliasTargetPropName; } } // 找到对应的 get PropertyDescriptor getter = names.get(propName); // 没有 get 跳出 if (getter == null) { continue; } MethodInfo read = ReflectUtils.getMethodInfo(getter.getReadMethod()); Method writeMethod = setter.getWriteMethod(); MethodInfo write = ReflectUtils.getMethodInfo(writeMethod); Type returnType = read.getSignature().getReturnType(); Type setterType = write.getSignature().getArgumentTypes()[0]; Class getterPropertyType = getter.getPropertyType(); Class setterPropertyType = setter.getPropertyType(); // macro 2019.01.12 优化逻辑,先判断类型,类型一致直接 set,不同再判断 是否 类型转换 // nonNull Label Label l0 = e.make_label(); // 判断类型是否一致,包括 包装类型 if (ClassUtil.isAssignable(setterPropertyType, getterPropertyType)) { // 2018.12.27 by macro 支持链式 bean e.load_local(targetLocal); e.load_local(sourceLocal); e.invoke(read); boolean getterIsPrimitive = getterPropertyType.isPrimitive(); boolean setterIsPrimitive = setterPropertyType.isPrimitive(); if (nonNull) { // 需要落栈,强制装箱 e.box(returnType); Local var = e.make_local(); e.store_local(var); e.load_local(var); // nonNull Label e.ifnull(l0); e.load_local(targetLocal); e.load_local(var); // 需要落栈,强制拆箱 e.unbox_or_zero(setterType); } else { // 如果 get 为原始类型,需要装箱 if (getterIsPrimitive && !setterIsPrimitive) { e.box(returnType); } // 如果 set 为原始类型,需要拆箱 if (!getterIsPrimitive && setterIsPrimitive) { e.unbox_or_zero(setterType); } } // 构造 set 方法 invokeWrite(e, write, writeMethod, nonNull, l0); } else if (useConverter) { e.load_local(targetLocal); e.load_arg(2); e.load_local(sourceLocal); e.invoke(read); e.box(returnType); if (nonNull) { Local var = e.make_local(); e.store_local(var); e.load_local(var); e.ifnull(l0); e.load_local(targetLocal); e.load_arg(2); e.load_local(var); } EmitUtils.load_class(e, setterType); // 更改成了属性名,之前是 set 方法名 e.push(propName); e.invoke_interface(CONVERTER, CONVERT); e.unbox_or_zero(setterType); // 构造 set 方法 invokeWrite(e, write, writeMethod, nonNull, l0); } } e.return_value(); e.end_method(); ce.end_class(); } /** * Invoke write. * * @param e the e * @param write the write * @param writeMethod the write method * @param nonNull the non null * @param l0 the l 0 */ private static void invokeWrite(CodeEmitter e, MethodInfo write, Method writeMethod, boolean nonNull, Label l0) { // 返回值,判断 链式 bean Class returnType = writeMethod.getReturnType(); e.invoke(write); // 链式 bean,有返回值需要 pop if (!returnType.equals(Void.TYPE)) { e.pop(); } if (nonNull) { e.visitLabel(l0); } } /** *

Title: firstInstance

*

Description:

. * * @param type the type * @return the object * @see org.springframework.cglib.core.AbstractClassGenerator#firstInstance(java.lang.Class) */ @Override protected Object firstInstance(Class type) { return BeanUtil.newInstance(type); } /** *

Title: nextInstance

*

Description:

. * * @param instance the instance * @return Object the object * @see org.springframework.cglib.core.AbstractClassGenerator#nextInstance(java.lang.Object) */ @Override protected Object nextInstance(Object instance) { return instance; } /** * 处理 map 的 copy. * * @param ce ClassEmitter * @param e CodeEmitter * @param sourceType sourceType * @param targetType targetType */ public void generateClassFormMap(ClassEmitter ce, CodeEmitter e, Type sourceType, Type targetType) { // 2018.12.27 by macro 支持链式 bean PropertyDescriptor[] setters = ReflectUtil.getBeanSetters(target); // 入口变量 Local targetLocal = e.make_local(); Local sourceLocal = e.make_local(); e.load_arg(1); e.checkcast(targetType); e.store_local(targetLocal); e.load_arg(0); e.checkcast(sourceType); e.store_local(sourceLocal); Type mapBox = Type.getType(Object.class); for (PropertyDescriptor setter : setters) { String propName = setter.getName(); // set 上有忽略的 注解 CopyProperty targetIgnoreCopy = ReflectUtil.getAnnotation(target, propName, CopyProperty.class); if (targetIgnoreCopy != null) { if (targetIgnoreCopy.ignore()) { continue; } // 注解上的别名 String aliasTargetPropName = targetIgnoreCopy.value(); if (StringUtil.isNotBlank(aliasTargetPropName)) { propName = aliasTargetPropName; } } Method writeMethod = setter.getWriteMethod(); MethodInfo write = ReflectUtils.getMethodInfo(writeMethod); Type setterType = write.getSignature().getArgumentTypes()[0]; e.load_local(targetLocal); e.load_local(sourceLocal); e.push(propName); // 执行 map get e.invoke_interface(BEAN_MAP, BEAN_MAP_GET); // box 装箱,避免 array[] 数组问题 e.box(mapBox); // 生成变量 Local var = e.make_local(); e.store_local(var); e.load_local(var); // 先判断 不为null,然后做类型判断 Label l0 = e.make_label(); e.ifnull(l0); EmitUtils.load_class(e, setterType); e.load_local(var); // ClassUtils.isAssignableValue(Integer.class, id) e.invoke_static(CLASS_UTILS, IS_ASSIGNABLE_VALUE); Label l1 = new Label(); // 返回值,判断 链式 bean Class returnType = writeMethod.getReturnType(); if (useConverter) { e.if_jump(Opcodes.IFEQ, l1); e.load_local(targetLocal); e.load_local(var); e.unbox_or_zero(setterType); e.invoke(write); if (!returnType.equals(Void.TYPE)) { e.pop(); } e.goTo(l0); e.visitLabel(l1); e.load_local(targetLocal); e.load_arg(2); e.load_local(var); EmitUtils.load_class(e, setterType); e.push(propName); e.invoke_interface(CONVERTER, CONVERT); e.unbox_or_zero(setterType); e.invoke(write); } else { e.if_jump(Opcodes.IFEQ, l0); e.load_local(targetLocal); e.load_local(var); e.unbox_or_zero(setterType); e.invoke(write); } // 返回值,判断 链式 bean if (!returnType.equals(Void.TYPE)) { e.pop(); } e.visitLabel(l0); } e.return_value(); e.end_method(); ce.end_class(); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy