Skip to content
This repository has been archived by the owner on Nov 21, 2024. It is now read-only.

Commit

Permalink
修复并发问题
Browse files Browse the repository at this point in the history
  • Loading branch information
tanyaofei committed Jan 12, 2023
1 parent 7b0edb3 commit 955a019
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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<BeanProperty> setters = Reflections.getBeanSetters(tc, configuration.isIncludingSuper());
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -188,7 +188,7 @@ private void writeConvertBridgeMethod(
/**
* 编写用于集合嵌套拷贝避免空指针错误的 lambda 方法
* <pre>{@code
* (Function)(varx1) -> {return varx1 == null ? null : this.convert(varx1);};
* (Function)(v) -> {return v == null ? null : this.convert(v);};
* }</pre>
*
* @param cw ClassWriter
Expand Down Expand Up @@ -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());
}

/**
Expand Down Expand Up @@ -262,6 +271,9 @@ && getCollectionElementType(sf) == sc

/**
* 集合嵌套拷贝
* <pre>{@code
* target.setValue(source.getValue().stream(v -> v == null ? null : this.convert(v)));
* }</pre>
*
* @param v MethodVisitor
* @param getter 来源字段的 getter 方法
Expand All @@ -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(),
Expand Down Expand Up @@ -322,7 +334,7 @@ private void nestedCollectionCopy(
/**
* 类型兼容拷贝
* <pre>{@code
* var2.setValue(var1.getValue());
* target.setValue(source.getValue());
* }</pre>
*
* @param v MethodVisit
Expand Down Expand Up @@ -372,13 +384,15 @@ private Label skipNull(MethodVisitor v, Method getter) {

/**
* 嵌套拷贝
* <pre>{@code
* target.setValue(this.convert(source.getValue()));
* }</pre>
*
* @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);
Expand Down
39 changes: 20 additions & 19 deletions src/main/java/io/github/tanyaofei/beancopier/ConverterFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class ConverterFactory implements Opcodes, MethodConstants {
/**
* 每个 classloader 已经注册的类名
*/
private final static WeakHashMap<ClassLoader, Set<String>> classNames = new WeakHashMap<>(4);
private final static WeakHashMap<ClassLoader, Set<String>> reservedClassNames = new WeakHashMap<>(4);

private final ConverterConfiguration configuration;

Expand Down Expand Up @@ -101,14 +101,26 @@ private static void dumpClass(byte[] code, String filename) {
}
}

private static Set<String> getReservedClassNames(ClassLoader cl) {
Set<String> names = reservedClassNames.get(cl);
if (names == null) {
synchronized (reservedClassNames) {
names = reservedClassNames.computeIfAbsent(cl, k -> new HashSet<>(32));
}
}
return names;
}

/**
* 创建 sc 拷贝为 tc 的转换器并加载到运行时内存中并创建实例
*
* @param sc 拷贝来源类
* @param tc 拷贝目标类
* @param <S> 拷贝来源
* @param <T> 拷贝目标
* @return sc to tc 转换器实例
* @return 将来源拷贝到目标的转换器
* @throws ConverterGenerateException 生成转换器字节码时发生异常
* @throws ConverterNewInstanceException 初始化转换器发生异常
*/
@Contract(pure = true)
@SuppressWarnings("unchecked")
Expand All @@ -122,10 +134,10 @@ public <S, T> Converter<S, T> generateConverter(
ClassLoader cl = Optional.ofNullable(configuration.getClassLoader()).orElse(chooseClassLoader(sc, tc));
// 生成类名称
String className;
Set<String> reservedClassNames = getClassLoaderReversedNames(cl);
synchronized (reservedClassNames) {
className = configuration.getNamingPolicy().getClassName(sc, tc, reservedClassNames::contains);
reservedClassNames.add(className);
Set<String> classNames = getReservedClassNames(cl);
synchronized (classNames) {
className = configuration.getNamingPolicy().getClassName(sc, tc, classNames::contains);
classNames.add(className);
}

Class<Converter<S, T>> c;
Expand All @@ -142,8 +154,8 @@ public <S, T> Converter<S, T> generateConverter(
c = (Class<Converter<S, T>>) 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);
}
Expand All @@ -170,17 +182,6 @@ private void checkSourceType(Class<?> c) {
}
}

private Set<String> getClassLoaderReversedNames(ClassLoader cl) {
Set<String> 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();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit 955a019

Please # to comment.