mirror of
https://github.com/alibaba/testable-mock.git
synced 2025-01-09 20:00:21 +08:00
fix an omni constructor issue caused by array-in-array type
This commit is contained in:
parent
338c7828c8
commit
db771b9c66
@ -7,7 +7,9 @@ import com.alibaba.testable.agent.util.CollectionUtil;
|
|||||||
import org.objectweb.asm.Label;
|
import org.objectweb.asm.Label;
|
||||||
import org.objectweb.asm.tree.*;
|
import org.objectweb.asm.tree.*;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import static com.alibaba.testable.agent.util.ClassUtil.CLASS_OBJECT;
|
import static com.alibaba.testable.agent.util.ClassUtil.CLASS_OBJECT;
|
||||||
import static com.alibaba.testable.core.constant.ConstPool.CONSTRUCTOR;
|
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 VOID_METHOD = "()V";
|
||||||
private static final String ENABLE_CONFIGURATION = "Lorg/springframework/context/annotation/Configuration;";
|
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_ABSTRACT_COLLECTION = "java/util/AbstractCollection";
|
||||||
|
private static final String CLASS_NUMBER = "java/lang/Number";
|
||||||
|
|
||||||
private static final String[] JUNIT_TEST_ANNOTATIONS = new String[] {
|
private static final String[] JUNIT_TEST_ANNOTATIONS = new String[] {
|
||||||
JUnit4Framework.ANNOTATION_TEST, JUnit5Framework.ANNOTATION_TEST, JUnit5Framework.ANNOTATION_PARAMETERIZED_TEST
|
JUnit4Framework.ANNOTATION_TEST, JUnit5Framework.ANNOTATION_TEST, JUnit5Framework.ANNOTATION_PARAMETERIZED_TEST
|
||||||
};
|
};
|
||||||
|
private static final Set<String> UNREACHABLE_CLASSES = new HashSet<String>() {{
|
||||||
|
add(CLASS_ABSTRACT_COLLECTION); add(CLASS_NUMBER);
|
||||||
|
}};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void transform(ClassNode cn) {
|
protected void transform(ClassNode cn) {
|
||||||
@ -114,7 +120,7 @@ public class OmniClassHandler extends BaseClassHandler {
|
|||||||
InsnList il = new InsnList();
|
InsnList il = new InsnList();
|
||||||
il.add(start);
|
il.add(start);
|
||||||
il.add(new VarInsnNode(ALOAD, 0));
|
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));
|
il.add(new MethodInsnNode(INVOKESPECIAL, cn.superName, CONSTRUCTOR, VOID_METHOD, false));
|
||||||
} else {
|
} else {
|
||||||
il.add(new VarInsnNode(ALOAD, 1));
|
il.add(new VarInsnNode(ALOAD, 1));
|
||||||
|
@ -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
|
* 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();
|
public MockClassParser mockClassParser = new MockClassParser();
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ import static com.alibaba.testable.core.constant.ConstPool.DOLLAR;
|
|||||||
public class OmniConstructor {
|
public class OmniConstructor {
|
||||||
|
|
||||||
private static final int INITIAL_CAPACITY = 6;
|
private static final int INITIAL_CAPACITY = 6;
|
||||||
|
private static final int FIRST = 1;
|
||||||
|
|
||||||
private OmniConstructor() {}
|
private OmniConstructor() {}
|
||||||
|
|
||||||
@ -155,7 +156,7 @@ public class OmniConstructor {
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T> void handleCircleReference(T instance, Class<?> type, Map<Class<?>, Object> classPool)
|
private static void handleCircleReference(Object instance, Class<?> type, Map<Class<?>, Object> classPool)
|
||||||
throws IllegalAccessException {
|
throws IllegalAccessException {
|
||||||
if (instance == null) {
|
if (instance == null) {
|
||||||
// don't travel null object
|
// don't travel null object
|
||||||
@ -173,13 +174,11 @@ public class OmniConstructor {
|
|||||||
Class<?> fieldType = f.getType();
|
Class<?> fieldType = f.getType();
|
||||||
if (fieldType.isArray()) {
|
if (fieldType.isArray()) {
|
||||||
Class<?> componentType = fieldType.getComponentType();
|
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());
|
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++) {
|
handleCircleReferenceOfArrayField(fieldIns, componentType, classPool);
|
||||||
handleCircleReference(Array.get(fieldIns, i), componentType, classPool);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (!fieldType.isPrimitive() && !TypeUtil.isBasicType(fieldType)) {
|
} else if (!TypeUtil.isBasicType(fieldType)) {
|
||||||
if (fieldIns == null && classPool.containsKey(fieldType)) {
|
if (fieldIns == null && classPool.containsKey(fieldType)) {
|
||||||
f.set(instance, classPool.get(fieldType));
|
f.set(instance, classPool.get(fieldType));
|
||||||
} else if (!classPool.containsKey(fieldType)) {
|
} else if (!classPool.containsKey(fieldType)) {
|
||||||
@ -191,6 +190,22 @@ public class OmniConstructor {
|
|||||||
classPool.remove(type);
|
classPool.remove(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void handleCircleReferenceOfArrayField(Object instance, Class<?> type, Map<Class<?>, 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<Class<?>> classPool)
|
private static Object createInstance(Class<?> clazz, Set<Class<?>> classPool)
|
||||||
throws InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
|
throws InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
|
||||||
Constructor<?> constructor = getBestConstructor(clazz);
|
Constructor<?> constructor = getBestConstructor(clazz);
|
||||||
|
@ -105,10 +105,10 @@ public class TypeUtil {
|
|||||||
* @param clazz type to check
|
* @param clazz type to check
|
||||||
*/
|
*/
|
||||||
public static boolean isBasicType(Class<?> clazz) {
|
public static boolean isBasicType(Class<?> clazz) {
|
||||||
return clazz.isEnum() || clazz.equals(Integer.class) || clazz.equals(Short.class) || clazz.equals(Long.class)
|
return clazz.isPrimitive() || clazz.isEnum() || clazz.equals(Integer.class) || clazz.equals(Short.class)
|
||||||
|| clazz.equals(Byte.class) || clazz.equals(Character.class) || clazz.equals(Float.class)
|
|| clazz.equals(Long.class) || clazz.equals(Byte.class) || clazz.equals(Character.class)
|
||||||
|| clazz.equals(Double.class) || clazz.equals(Boolean.class) || clazz.equals(Class.class)
|
|| clazz.equals(Float.class) || clazz.equals(Double.class) || clazz.equals(Boolean.class)
|
||||||
|| clazz.equals(String.class) || clazz.equals(Date.class);
|
|| clazz.equals(Class.class) || clazz.equals(String.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user