diff --git a/src/main/java/io/github/tanyaofei/beancopier/ConverterCodeWriter.java b/src/main/java/io/github/tanyaofei/beancopier/ConverterCodeWriter.java index 28280b2..704ae70 100644 --- a/src/main/java/io/github/tanyaofei/beancopier/ConverterCodeWriter.java +++ b/src/main/java/io/github/tanyaofei/beancopier/ConverterCodeWriter.java @@ -95,7 +95,7 @@ private void writeConvertMethod(ClassWriter cw) { v.visitCode(); - CodeEmitter.newInstanceViaNoArgsConstructor(v, tc); + CodeEmitter.newInstance(v, tc); v.visitVarInsn(ASTORE, 2); Label jumpHere = null; Iterable setters = Reflections.getBeanSetters(tc, configuration.isIncludingSuper()); @@ -133,7 +133,7 @@ private void writeConvertMethod(ClassWriter cw) { jumpHere = skipNull(v, getter); nestedCollectionCopy(v, getter, setter); hasNestedCollectionCopy = true; - } else if (isCompatible(sf, tf)) { + } else if (configuration.isFullTypeMatching() ? isTypeEquals(sf, tf) : isCompatible(sf, tf)) { if (jumpHere != null) { v.visitLabel(jumpHere); } @@ -188,7 +188,7 @@ private void writeConvertBridgeMethod( /** * 编写用于集合嵌套拷贝避免空指针错误的 lambda 方法 *
{@code
-   * (Function)(varx1) -> {return varx1 == null ? null : this.convert(varx1);};
+   * (Function)(v) -> {return v == null ? null : this.convert(v);};
    * }
* * @param cw ClassWriter @@ -229,12 +229,21 @@ private void writeConvertBridgeMethod( * * @param sf 来源字段 * @param tf 目标字段 - * @return 如果配置了全类型匹配,则严格判断两者的类型是否完全一致;否则会根据 JAVA 的规范判断是否兼容 + * @return 两个字段类型是否兼容 */ private boolean isCompatible(Field sf, Field tf) { - return configuration.isFullTypeMatching() - ? sf.getGenericType().equals(tf.getGenericType()) - : TypeToken.of(sf.getGenericType()).isSubtypeOf(tf.getGenericType()); + return TypeToken.of(sf.getGenericType()).isSubtypeOf(tf.getGenericType()); + } + + /** + * 判断类型是否相同 + * + * @param sf 来源字段 + * @param tf 目标字段 + * @return 两个字段的类型是否相同 + */ + private boolean isTypeEquals(Field sf, Field tf) { + return sf.getGenericType().equals(tf.getGenericType()); } /** @@ -262,6 +271,9 @@ && getCollectionElementType(sf) == sc /** * 集合嵌套拷贝 + *
{@code
+   * target.setValue(source.getValue().stream(v -> v == null ? null : this.convert(v)));
+   * }
* * @param v MethodVisitor * @param getter 来源字段的 getter 方法 @@ -275,14 +287,14 @@ private void nestedCollectionCopy( String methodDescriptor = CodeEmitter.getMethodDescriptor(tc, sc); v.visitVarInsn(ALOAD, 2); - // this.getField() + // this.getValue() v.visitVarInsn(ALOAD, 1); CodeEmitter.invokeMethod(v, INVOKEVIRTUAL, getter); // list.stream() CodeEmitter.invokeMethod(v, INVOKEINTERFACE, LIST$STREAM); - // (o) -> o == null ? null : this.convert(o) + // (v) -> v == null ? null : this.convert(v) v.visitVarInsn(ALOAD, 0); v.visitInvokeDynamicInsn( FUNCTION$APPLY.getName(), @@ -322,7 +334,7 @@ private void nestedCollectionCopy( /** * 类型兼容拷贝 *
{@code
-   * var2.setValue(var1.getValue());
+   * target.setValue(source.getValue());
    * }
* * @param v MethodVisit @@ -372,13 +384,15 @@ private Label skipNull(MethodVisitor v, Method getter) { /** * 嵌套拷贝 + *
{@code
+   * target.setValue(this.convert(source.getValue()));
+   * }
* * @param v MethodVisitor * @param getter 来源字段的 getter 方法 * @param setter 来源字段的 setter 方法 */ private void nestedCopy(MethodVisitor v, Method getter, Method setter) { - // target.setField(convert(source.getField())) v.visitVarInsn(ALOAD, 2); v.visitVarInsn(ALOAD, 0); v.visitVarInsn(ALOAD, 1); diff --git a/src/main/java/io/github/tanyaofei/beancopier/ConverterFactory.java b/src/main/java/io/github/tanyaofei/beancopier/ConverterFactory.java index 881723b..b2988da 100644 --- a/src/main/java/io/github/tanyaofei/beancopier/ConverterFactory.java +++ b/src/main/java/io/github/tanyaofei/beancopier/ConverterFactory.java @@ -36,7 +36,7 @@ class ConverterFactory implements Opcodes, MethodConstants { /** * 每个 classloader 已经注册的类名 */ - private final static WeakHashMap> classNames = new WeakHashMap<>(4); + private final static WeakHashMap> reservedClassNames = new WeakHashMap<>(4); private final ConverterConfiguration configuration; @@ -101,6 +101,16 @@ private static void dumpClass(byte[] code, String filename) { } } + private static Set getReservedClassNames(ClassLoader cl) { + Set names = reservedClassNames.get(cl); + if (names == null) { + synchronized (reservedClassNames) { + names = reservedClassNames.computeIfAbsent(cl, k -> new HashSet<>(32)); + } + } + return names; + } + /** * 创建 sc 拷贝为 tc 的转换器并加载到运行时内存中并创建实例 * @@ -108,7 +118,9 @@ private static void dumpClass(byte[] code, String filename) { * @param tc 拷贝目标类 * @param 拷贝来源 * @param 拷贝目标 - * @return sc to tc 转换器实例 + * @return 将来源拷贝到目标的转换器 + * @throws ConverterGenerateException 生成转换器字节码时发生异常 + * @throws ConverterNewInstanceException 初始化转换器发生异常 */ @Contract(pure = true) @SuppressWarnings("unchecked") @@ -122,10 +134,10 @@ public Converter generateConverter( ClassLoader cl = Optional.ofNullable(configuration.getClassLoader()).orElse(chooseClassLoader(sc, tc)); // 生成类名称 String className; - Set reservedClassNames = getClassLoaderReversedNames(cl); - synchronized (reservedClassNames) { - className = configuration.getNamingPolicy().getClassName(sc, tc, reservedClassNames::contains); - reservedClassNames.add(className); + Set classNames = getReservedClassNames(cl); + synchronized (classNames) { + className = configuration.getNamingPolicy().getClassName(sc, tc, classNames::contains); + classNames.add(className); } Class> c; @@ -142,8 +154,8 @@ public Converter generateConverter( c = (Class>) unsafe.defineClass(null, code, 0, code.length, cl, null); } } catch (Exception e) { - synchronized (reservedClassNames) { - reservedClassNames.remove(className); + synchronized (classNames) { + classNames.remove(className); } throw new ConverterGenerateException(sc, tc, e); } @@ -170,17 +182,6 @@ private void checkSourceType(Class c) { } } - private Set getClassLoaderReversedNames(ClassLoader cl) { - Set names = classNames.get(cl); - if (names == null) { - synchronized (classNames) { - names = new HashSet<>(32); - classNames.put(cl, names); - } - } - return names; - } - private void checkTargetType(Class c) { int modifiers = c.getModifiers(); diff --git a/src/main/java/io/github/tanyaofei/beancopier/utils/CodeEmitter.java b/src/main/java/io/github/tanyaofei/beancopier/utils/CodeEmitter.java index e231f15..74acf73 100644 --- a/src/main/java/io/github/tanyaofei/beancopier/utils/CodeEmitter.java +++ b/src/main/java/io/github/tanyaofei/beancopier/utils/CodeEmitter.java @@ -111,7 +111,7 @@ public static void newObject(MethodVisitor v, Class objType) { v.visitTypeInsn(NEW, Type.getInternalName(objType)); } - public static void newInstanceViaNoArgsConstructor(MethodVisitor v, Class objType) { + public static void newInstance(MethodVisitor v, Class objType) { newObject(v, objType); v.visitInsn(DUP); invokeNoArgsConstructor(v, objType);