org.macrocloud.kernel.toolkit.beans.BeanCopier Maven / Gradle / Ivy
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