From db771b9c66e46bc82a53ce2d94f37abf76175e30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=87=91=E6=88=9F?= Date: Sun, 25 Apr 2021 18:24:13 +0800 Subject: [PATCH] fix an omni constructor issue caused by array-in-array type --- .../agent/handler/OmniClassHandler.java | 8 +++++- .../transformer/TestableClassTransformer.java | 3 ++- .../testable/core/tool/OmniConstructor.java | 27 ++++++++++++++----- .../alibaba/testable/core/util/TypeUtil.java | 8 +++--- 4 files changed, 34 insertions(+), 12 deletions(-) diff --git a/testable-agent/src/main/java/com/alibaba/testable/agent/handler/OmniClassHandler.java b/testable-agent/src/main/java/com/alibaba/testable/agent/handler/OmniClassHandler.java index 084b06f..2a56869 100644 --- a/testable-agent/src/main/java/com/alibaba/testable/agent/handler/OmniClassHandler.java +++ b/testable-agent/src/main/java/com/alibaba/testable/agent/handler/OmniClassHandler.java @@ -7,7 +7,9 @@ import com.alibaba.testable.agent.util.CollectionUtil; import org.objectweb.asm.Label; import org.objectweb.asm.tree.*; +import java.util.HashSet; import java.util.List; +import java.util.Set; import static com.alibaba.testable.agent.util.ClassUtil.CLASS_OBJECT; import static com.alibaba.testable.core.constant.ConstPool.CONSTRUCTOR; @@ -25,10 +27,14 @@ public class OmniClassHandler extends BaseClassHandler { private static final String VOID_METHOD = "()V"; private static final String ENABLE_CONFIGURATION = "Lorg/springframework/context/annotation/Configuration;"; private static final String CLASS_ABSTRACT_COLLECTION = "java/util/AbstractCollection"; + private static final String CLASS_NUMBER = "java/lang/Number"; private static final String[] JUNIT_TEST_ANNOTATIONS = new String[] { JUnit4Framework.ANNOTATION_TEST, JUnit5Framework.ANNOTATION_TEST, JUnit5Framework.ANNOTATION_PARAMETERIZED_TEST }; + private static final Set UNREACHABLE_CLASSES = new HashSet() {{ + add(CLASS_ABSTRACT_COLLECTION); add(CLASS_NUMBER); + }}; @Override protected void transform(ClassNode cn) { @@ -114,7 +120,7 @@ public class OmniClassHandler extends BaseClassHandler { InsnList il = new InsnList(); il.add(start); il.add(new VarInsnNode(ALOAD, 0)); - if (cn.superName.equals(CLASS_ABSTRACT_COLLECTION)) { + if (UNREACHABLE_CLASSES.contains(cn.superName)) { il.add(new MethodInsnNode(INVOKESPECIAL, cn.superName, CONSTRUCTOR, VOID_METHOD, false)); } else { il.add(new VarInsnNode(ALOAD, 1)); diff --git a/testable-agent/src/main/java/com/alibaba/testable/agent/transformer/TestableClassTransformer.java b/testable-agent/src/main/java/com/alibaba/testable/agent/transformer/TestableClassTransformer.java index 0093e29..292854f 100644 --- a/testable-agent/src/main/java/com/alibaba/testable/agent/transformer/TestableClassTransformer.java +++ b/testable-agent/src/main/java/com/alibaba/testable/agent/transformer/TestableClassTransformer.java @@ -39,7 +39,8 @@ public class TestableClassTransformer implements ClassFileTransformer { /** * Just avoid spend time to scan those surely non-user classes, should keep these lists as tiny as possible */ - private final String[] BLACKLIST_PREFIXES = new String[] { "sun/", "com/sun/", "javax/crypto", "org/gradle/" }; + private final String[] BLACKLIST_PREFIXES = new String[] { "sun/", "com/sun/", "javax/crypto", "java/util/logging", + "org/gradle/" }; public MockClassParser mockClassParser = new MockClassParser(); diff --git a/testable-core/src/main/java/com/alibaba/testable/core/tool/OmniConstructor.java b/testable-core/src/main/java/com/alibaba/testable/core/tool/OmniConstructor.java index 0bdabb0..2ed8687 100644 --- a/testable-core/src/main/java/com/alibaba/testable/core/tool/OmniConstructor.java +++ b/testable-core/src/main/java/com/alibaba/testable/core/tool/OmniConstructor.java @@ -15,6 +15,7 @@ import static com.alibaba.testable.core.constant.ConstPool.DOLLAR; public class OmniConstructor { private static final int INITIAL_CAPACITY = 6; + private static final int FIRST = 1; private OmniConstructor() {} @@ -155,7 +156,7 @@ public class OmniConstructor { return instance; } - private static void handleCircleReference(T instance, Class type, Map, Object> classPool) + private static void handleCircleReference(Object instance, Class type, Map, Object> classPool) throws IllegalAccessException { if (instance == null) { // don't travel null object @@ -173,13 +174,11 @@ public class OmniConstructor { Class fieldType = f.getType(); if (fieldType.isArray()) { Class componentType = fieldType.getComponentType(); - if (fieldIns != null && !componentType.isPrimitive() && !TypeUtil.isBasicType(componentType)) { + if (fieldIns != null && !TypeUtil.isBasicType(componentType)) { LogUtil.verbose(classPool.size(), "Field(Array[%d]) %s", Array.getLength(fieldIns), f.getName()); - for (int i = 0; i < Math.min(Array.getLength(fieldIns), 10); i++) { - handleCircleReference(Array.get(fieldIns, i), componentType, classPool); - } + handleCircleReferenceOfArrayField(fieldIns, componentType, classPool); } - } else if (!fieldType.isPrimitive() && !TypeUtil.isBasicType(fieldType)) { + } else if (!TypeUtil.isBasicType(fieldType)) { if (fieldIns == null && classPool.containsKey(fieldType)) { f.set(instance, classPool.get(fieldType)); } else if (!classPool.containsKey(fieldType)) { @@ -191,6 +190,22 @@ public class OmniConstructor { classPool.remove(type); } + private static void handleCircleReferenceOfArrayField(Object instance, Class type, Map, Object> classPool) + throws IllegalAccessException { + if (type.isArray()) { + for (int i = 0; i < Math.min(Array.getLength(instance), FIRST); i++) { + Object arrayIns = Array.get(instance, i); + if (arrayIns != null) { + handleCircleReferenceOfArrayField(arrayIns, arrayIns.getClass().getComponentType(), classPool); + } + } + } else if (!classPool.containsKey(type)) { + for (int i = 0; i < Math.min(Array.getLength(instance), FIRST); i++) { + handleCircleReference(Array.get(instance, i), type, classPool); + } + } + } + private static Object createInstance(Class clazz, Set> classPool) throws InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { Constructor constructor = getBestConstructor(clazz); diff --git a/testable-core/src/main/java/com/alibaba/testable/core/util/TypeUtil.java b/testable-core/src/main/java/com/alibaba/testable/core/util/TypeUtil.java index f1bfee5..3834c38 100644 --- a/testable-core/src/main/java/com/alibaba/testable/core/util/TypeUtil.java +++ b/testable-core/src/main/java/com/alibaba/testable/core/util/TypeUtil.java @@ -105,10 +105,10 @@ public class TypeUtil { * @param clazz type to check */ public static boolean isBasicType(Class clazz) { - return clazz.isEnum() || clazz.equals(Integer.class) || clazz.equals(Short.class) || clazz.equals(Long.class) - || clazz.equals(Byte.class) || clazz.equals(Character.class) || clazz.equals(Float.class) - || clazz.equals(Double.class) || clazz.equals(Boolean.class) || clazz.equals(Class.class) - || clazz.equals(String.class) || clazz.equals(Date.class); + return clazz.isPrimitive() || clazz.isEnum() || clazz.equals(Integer.class) || clazz.equals(Short.class) + || clazz.equals(Long.class) || clazz.equals(Byte.class) || clazz.equals(Character.class) + || clazz.equals(Float.class) || clazz.equals(Double.class) || clazz.equals(Boolean.class) + || clazz.equals(Class.class) || clazz.equals(String.class); } /**