diff --git a/testable-agent/src/main/java/com/alibaba/testable/agent/constant/ConstPool.java b/testable-agent/src/main/java/com/alibaba/testable/agent/constant/ConstPool.java index ffa79fd..581e20d 100644 --- a/testable-agent/src/main/java/com/alibaba/testable/agent/constant/ConstPool.java +++ b/testable-agent/src/main/java/com/alibaba/testable/agent/constant/ConstPool.java @@ -8,6 +8,7 @@ public class ConstPool { public static final String FIELD_TARGET_METHOD = "targetMethod"; public static final String FIELD_TARGET_CLASS = "targetClass"; public static final String FIELD_SCOPE = "scope"; + public static final String FIELD_VALUE = "value"; public static final String PROPERTY_USER_DIR = "user.dir"; public static final String PROPERTY_TEMP_DIR = "java.io.tmpdir"; 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 ba3f986..00f0bba 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 @@ -22,10 +22,10 @@ import java.lang.instrument.ClassFileTransformer; import java.security.ProtectionDomain; import java.util.List; -import static com.alibaba.testable.agent.constant.ConstPool.*; +import static com.alibaba.testable.agent.constant.ConstPool.CGLIB_CLASS_PATTERN; +import static com.alibaba.testable.agent.constant.ConstPool.KOTLIN_POSTFIX_COMPANION; import static com.alibaba.testable.core.constant.ConstPool.DOLLAR; import static com.alibaba.testable.core.constant.ConstPool.TEST_POSTFIX; -import static com.alibaba.testable.core.util.PathUtil.createFolder; import static org.objectweb.asm.Opcodes.ACC_STATIC; /** @@ -33,7 +33,6 @@ import static org.objectweb.asm.Opcodes.ACC_STATIC; */ public class TestableClassTransformer implements ClassFileTransformer { - private static final String FIELD_VALUE = "value"; private static final String FIELD_TREAT_AS = "treatAs"; private static final String CLASS_JUNIT_5_NESTED = "Lorg/junit/jupiter/api/Nested;"; @@ -71,7 +70,7 @@ public class TestableClassTransformer implements ClassFileTransformer { if (mockClassParser.isMockClass(cn)) { // it's a mock class bytes = new MockClassHandler(className).getBytes(bytes); - BytecodeUtil.dumpByte(className, GlobalConfig.getDumpPath(), bytes); + BytecodeUtil.dumpByte(cn, GlobalConfig.getDumpPath(), bytes); return bytes; } String mockClass = foundMockForSourceClass(className); @@ -79,14 +78,14 @@ public class TestableClassTransformer implements ClassFileTransformer { // it's a source class with testable enabled List injectMethods = mockClassParser.getTestableMockMethods(mockClass); bytes = new SourceClassHandler(injectMethods, mockClass).getBytes(bytes); - BytecodeUtil.dumpByte(className, GlobalConfig.getDumpPath(), bytes); + BytecodeUtil.dumpByte(cn, GlobalConfig.getDumpPath(), bytes); return bytes; } Framework framework = testClassChecker.checkFramework(cn); if (framework != null) { // it's a test class bytes = new TestClassHandler(framework).getBytes(bytes); - BytecodeUtil.dumpByte(className, GlobalConfig.getDumpPath(), bytes); + BytecodeUtil.dumpByte(cn, GlobalConfig.getDumpPath(), bytes); return bytes; } else if (cn.name.endsWith(TEST_POSTFIX)) { LogUtil.verbose("Failed to detect test framework for %s", cn.name); @@ -101,7 +100,7 @@ public class TestableClassTransformer implements ClassFileTransformer { } finally { LogUtil.resetLogLevel(); } - BytecodeUtil.dumpByte(className, getDumpPathByAnnotation(cn), bytes); + BytecodeUtil.dumpByte(cn, null, bytes); return bytes; } @@ -257,7 +256,7 @@ public class TestableClassTransformer implements ClassFileTransformer { ClassType type = AnnotationUtil.getAnnotationParameter(an, FIELD_TREAT_AS, ClassType.GuessByName, ClassType.class); if (isExpectedType(cn.name, type, expectedType)) { - Type clazz = AnnotationUtil.getAnnotationParameter(an, FIELD_VALUE, + Type clazz = AnnotationUtil.getAnnotationParameter(an, ConstPool.FIELD_VALUE, Type.getType(NullType.class), Type.class); DiagnoseUtil.setupByClass(ClassUtil.getClassNode(clazz.getClassName())); return clazz.getClassName(); @@ -268,21 +267,6 @@ public class TestableClassTransformer implements ClassFileTransformer { return null; } - private String getDumpPathByAnnotation(ClassNode cn) { - if (cn.visibleAnnotations != null) { - for (AnnotationNode an : cn.visibleAnnotations) { - if ((ClassUtil.toByteCodeClassName(ConstPool.DUMP_TO)).equals(an.desc)) { - String path = AnnotationUtil.getAnnotationParameter(an, FIELD_VALUE, null, String.class); - String fullPath = PathUtil.join(System.getProperty(PROPERTY_USER_DIR), path); - if (createFolder(fullPath)) { - return fullPath; - } - } - } - } - return null; - } - private boolean isExpectedType(String className, ClassType type, ClassType expectedType) { if (type.equals(ClassType.GuessByName)) { return expectedType.equals(ClassType.TestClass) == className.endsWith(TEST_POSTFIX); diff --git a/testable-agent/src/main/java/com/alibaba/testable/agent/util/BytecodeUtil.java b/testable-agent/src/main/java/com/alibaba/testable/agent/util/BytecodeUtil.java index f1e45f9..ecd3636 100644 --- a/testable-agent/src/main/java/com/alibaba/testable/agent/util/BytecodeUtil.java +++ b/testable-agent/src/main/java/com/alibaba/testable/agent/util/BytecodeUtil.java @@ -1,19 +1,20 @@ package com.alibaba.testable.agent.util; import com.alibaba.testable.agent.constant.ByteCodeConst; +import com.alibaba.testable.agent.constant.ConstPool; import com.alibaba.testable.agent.tool.ImmutablePair; import com.alibaba.testable.core.util.LogUtil; -import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.InsnNode; -import org.objectweb.asm.tree.IntInsnNode; +import org.objectweb.asm.tree.*; import java.io.FileOutputStream; import java.io.IOException; import java.util.HashMap; import java.util.Map; +import static com.alibaba.testable.agent.constant.ConstPool.FIELD_VALUE; +import static com.alibaba.testable.agent.constant.ConstPool.PROPERTY_USER_DIR; import static com.alibaba.testable.core.constant.ConstPool.*; -import static com.alibaba.testable.core.constant.ConstPool.UNDERLINE; +import static com.alibaba.testable.core.util.PathUtil.createFolder; import static org.objectweb.asm.Opcodes.*; /** @@ -21,6 +22,8 @@ import static org.objectweb.asm.Opcodes.*; */ public class BytecodeUtil { + private static final String POSTFIX_CLASS = ".class"; + /** * refer to https://en.wikipedia.org/wiki/Java_bytecode_instruction_listings * positive for push stack, negative for pop stack @@ -208,17 +211,20 @@ public class BytecodeUtil { /** * Dump byte code to specified class file - * @param className original class name + * @param cn original class node * @param dumpPath folder to store class file * @param bytes original class bytes */ - public static void dumpByte(String className, String dumpPath, byte[] bytes) { + public static void dumpByte(ClassNode cn, String dumpPath, byte[] bytes) { if (dumpPath == null) { - return; + dumpPath = getDumpPathByAnnotation(cn); + if (dumpPath == null) { + return; + } } try { String dumpFile = PathUtil.join(dumpPath, - className.replace(SLASH, DOT).replace(DOLLAR, UNDERLINE) + ".class"); + cn.name.replace(SLASH, DOT).replace(DOLLAR, UNDERLINE) + POSTFIX_CLASS); LogUtil.verbose("Dump class: " + dumpFile); FileOutputStream stream = new FileOutputStream(dumpFile); stream.write(bytes); @@ -275,4 +281,19 @@ public class BytecodeUtil { return new IntInsnNode(BIPUSH, num); } } + + private static String getDumpPathByAnnotation(ClassNode cn) { + if (cn.visibleAnnotations != null) { + for (AnnotationNode an : cn.visibleAnnotations) { + if ((ClassUtil.toByteCodeClassName(ConstPool.DUMP_TO)).equals(an.desc)) { + String path = AnnotationUtil.getAnnotationParameter(an, FIELD_VALUE, null, String.class); + String fullPath = PathUtil.join(System.getProperty(PROPERTY_USER_DIR), path); + if (createFolder(fullPath)) { + return fullPath; + } + } + } + } + return null; + } } diff --git a/testable-agent/src/main/java/com/alibaba/testable/agent/util/DiagnoseUtil.java b/testable-agent/src/main/java/com/alibaba/testable/agent/util/DiagnoseUtil.java index 1507cdf..50b29b2 100644 --- a/testable-agent/src/main/java/com/alibaba/testable/agent/util/DiagnoseUtil.java +++ b/testable-agent/src/main/java/com/alibaba/testable/agent/util/DiagnoseUtil.java @@ -8,15 +8,13 @@ import org.objectweb.asm.tree.ClassNode; public class DiagnoseUtil { - private static final String FIELD_VALUE = "value"; - public static void setupByClass(ClassNode cn) { if (cn == null || cn.visibleAnnotations == null) { return; } for (AnnotationNode an : cn.visibleAnnotations) { if (ClassUtil.toByteCodeClassName(ConstPool.MOCK_DIAGNOSE).equals(an.desc)) { - setupDiagnose(an, FIELD_VALUE); + setupDiagnose(an, ConstPool.FIELD_VALUE); } } }