From 80b6cbfc9c861469146318d0b3dd5f8b8b525b8a Mon Sep 17 00:00:00 2001 From: xiejun <xiejun@vci-tech.com> Date: 星期五, 01 十一月 2024 15:11:19 +0800 Subject: [PATCH] Revert "集成获取mdm分发通用数据格式接口集成" --- Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/beans/BladeBeanCopier.java | 405 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 405 insertions(+), 0 deletions(-) diff --git a/Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/beans/BladeBeanCopier.java b/Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/beans/BladeBeanCopier.java new file mode 100644 index 0000000..0dc0c33 --- /dev/null +++ b/Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/beans/BladeBeanCopier.java @@ -0,0 +1,405 @@ +/* + * 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 榄旀敼 + * + * <p> + * 1. 鏀寔閾惧紡 bean锛屾敮鎸� map + * 2. ClassLoader 璺� target 淇濇寔涓�鑷� + * </p> + * + * @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<BladeBeanCopierKey, BladeBeanCopier> 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<String, PropertyDescriptor> 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(); + } + } +} -- Gitblit v1.9.3