/* * Copyright (c) 2018-2028, DreamLu All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * Neither the name of the dreamlu.net developer nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * Author: DreamLu 卢春梦 (596392912@qq.com) */ package org.springblade.core.tool.beans; import org.springblade.core.tool.utils.BeanUtil; import org.springblade.core.tool.utils.ClassUtil; import org.springblade.core.tool.utils.ReflectUtil; import org.springblade.core.tool.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 L.cm */ public abstract class BladeBeanCopier { private static final Type CONVERTER = TypeUtils.parseType("org.springframework.cglib.core.Converter"); private static final Type BEAN_COPIER = TypeUtils.parseType(BladeBeanCopier.class.getName()); private static final Type BEAN_MAP = TypeUtils.parseType(Map.class.getName()); private static final Signature COPY = new Signature("copy", Type.VOID_TYPE, new Type[]{Constants.TYPE_OBJECT, Constants.TYPE_OBJECT, CONVERTER}); private static final Signature CONVERT = TypeUtils.parseSignature("Object convert(Object, Class, Object)"); private static final Signature BEAN_MAP_GET = TypeUtils.parseSignature("Object get(Object)"); private static final Type CLASS_UTILS = TypeUtils.parseType(ClassUtils.class.getName()); private static final Signature IS_ASSIGNABLE_VALUE = TypeUtils.parseSignature("boolean isAssignableValue(Class, Object)"); /** * The map to store {@link BladeBeanCopier} of source type and class type for copy. */ private static final ConcurrentMap BEAN_COPIER_MAP = new ConcurrentHashMap<>(); public static BladeBeanCopier create(Class source, Class target, boolean useConverter) { return BladeBeanCopier.create(source, target, useConverter, false); } public static BladeBeanCopier create(Class source, Class target, boolean useConverter, boolean nonNull) { BladeBeanCopierKey copierKey = new BladeBeanCopierKey(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); public static class Generator extends AbstractClassGenerator { private static final Source SOURCE = new Source(BladeBeanCopier.class.getName()); private Class source; private Class target; private boolean useConverter; private boolean nonNull; Generator() { super(SOURCE); } public void setSource(Class source) { if (!Modifier.isPublic(source.getModifiers())) { setNamePrefix(source.getName()); } this.source = source; } public void setTarget(Class target) { if (!Modifier.isPublic(target.getModifiers())) { setNamePrefix(target.getName()); } this.target = target; } public void setUseConverter(boolean useConverter) { this.useConverter = useConverter; } public void setNonNull(boolean nonNull) { this.nonNull = nonNull; } @Override protected ClassLoader getDefaultClassLoader() { // L.cm 保证 和 返回使用同一个 ClassLoader return target.getClassLoader(); } @Override protected ProtectionDomain getProtectionDomain() { return ReflectUtils.getProtectionDomain(source); } @Override public BladeBeanCopier create(Object key) { return (BladeBeanCopier) super.create(key); } @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 L.cm 支持链式 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(); // L.cm 2019.01.12 优化逻辑,先判断类型,类型一致直接 set,不同再判断 是否 类型转换 // nonNull Label Label l0 = e.make_label(); // 判断类型是否一致,包括 包装类型 if (ClassUtil.isAssignable(setterPropertyType, getterPropertyType)) { // 2018.12.27 by L.cm 支持链式 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(); } 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); } } @Override protected Object firstInstance(Class type) { return BeanUtil.newInstance(type); } @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 L.cm 支持链式 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(); } } }