From d91d972aa780678bd435f2d35a74372ee70ada7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=87=91=E6=88=9F?= Date: Wed, 22 Jul 2020 22:09:03 +0800 Subject: [PATCH] refactor n.e class to type util --- .../transformer/TestableClassTransformer.java | 2 +- .../testable/accessor/PrivateAccessor.java | 4 +- .../generator/TestSetupMethodGenerator.java | 6 +- .../com/alibaba/testable/util/ConstPool.java | 10 +- .../com/alibaba/testable/util/TypeUtil.java | 173 ++++++++++++++--- core/src/main/java/n/e.java | 64 ++++++ core/src/main/java/testable_internal/n/e.java | 182 ------------------ 7 files changed, 224 insertions(+), 217 deletions(-) create mode 100644 core/src/main/java/n/e.java delete mode 100644 core/src/main/java/testable_internal/n/e.java diff --git a/agent/src/main/java/com/alibaba/testable/transformer/TestableClassTransformer.java b/agent/src/main/java/com/alibaba/testable/transformer/TestableClassTransformer.java index 1409cea..dbb6659 100644 --- a/agent/src/main/java/com/alibaba/testable/transformer/TestableClassTransformer.java +++ b/agent/src/main/java/com/alibaba/testable/transformer/TestableClassTransformer.java @@ -20,7 +20,7 @@ import static com.alibaba.testable.constant.Const.SYS_CLASSES; public class TestableClassTransformer implements Opcodes { private static final String CONSTRUCTOR = ""; - private static final String TESTABLE_NE = "testable_internal/n/e"; + private static final String TESTABLE_NE = "n/e"; private final ClassNode cn = new ClassNode(); public TestableClassTransformer(String className) throws IOException { diff --git a/core/src/main/java/com/alibaba/testable/accessor/PrivateAccessor.java b/core/src/main/java/com/alibaba/testable/accessor/PrivateAccessor.java index 1dd4282..76d15c8 100644 --- a/core/src/main/java/com/alibaba/testable/accessor/PrivateAccessor.java +++ b/core/src/main/java/com/alibaba/testable/accessor/PrivateAccessor.java @@ -33,8 +33,8 @@ public class PrivateAccessor { public static T invoke(Object ref, String method, Object... args) { try { - Class[] cls = TypeUtil.gcs(args); - Method declaredMethod = TypeUtil.gm(ref.getClass().getDeclaredMethods(), method, cls); + Class[] cls = TypeUtil.getClassesFromObjects(args); + Method declaredMethod = TypeUtil.getMethodByNameAndParameterTypes(ref.getClass().getDeclaredMethods(), method, cls); declaredMethod.setAccessible(true); return (T)declaredMethod.invoke(ref, args); } catch (Exception e) { diff --git a/core/src/main/java/com/alibaba/testable/generator/TestSetupMethodGenerator.java b/core/src/main/java/com/alibaba/testable/generator/TestSetupMethodGenerator.java index dc14249..8e6294e 100644 --- a/core/src/main/java/com/alibaba/testable/generator/TestSetupMethodGenerator.java +++ b/core/src/main/java/com/alibaba/testable/generator/TestSetupMethodGenerator.java @@ -50,9 +50,9 @@ public class TestSetupMethodGenerator extends BaseGenerator { ListBuffer statements = new ListBuffer<>(); for (Pair>> m : injectMethods.toList()) { if (isMemberMethod(m)) { - statements.append(addToPoolStatement(m, ConstPool.NE_ADD_F)); + statements.append(addToPoolStatement(m, ConstPool.METHOD_ADD_TO_MEM_POOL)); } else { - statements.append(addToPoolStatement(m, ConstPool.NE_ADD_W)); + statements.append(addToPoolStatement(m, ConstPool.METHOD_ADD_TO_CON_POLL)); } } if (!testSetupMethodName.isEmpty()) { @@ -86,7 +86,7 @@ public class TestSetupMethodGenerator extends BaseGenerator { } private JCStatement addToPoolStatement(Pair>> m, String addPoolMethod) { - JCExpression pool = nameToExpression(ConstPool.NE_POOL); + JCExpression pool = nameToExpression(ConstPool.CLASS_SUBSTITUTION); JCExpression classType = m.snd.fst; JCExpression methodName = cx.treeMaker.Literal(m.fst.toString()); JCExpression parameterTypes = cx.treeMaker.NewArray(cx.treeMaker.Ident(cx.names.fromString(TYPE_CLASS)), diff --git a/core/src/main/java/com/alibaba/testable/util/ConstPool.java b/core/src/main/java/com/alibaba/testable/util/ConstPool.java index 2f1b7f3..bff9a1c 100644 --- a/core/src/main/java/com/alibaba/testable/util/ConstPool.java +++ b/core/src/main/java/com/alibaba/testable/util/ConstPool.java @@ -5,14 +5,14 @@ package com.alibaba.testable.util; */ public final class ConstPool { - public static final String NE_PKG = "testable_internal.n"; + public static final String NE_PKG = "n"; public static final String NE_CLS = "e"; public static final String NE_NEW = "w"; public static final String NE_FUN = "f"; - public static final String NE_PKG_CLS = NE_PKG + "." + NE_CLS; - public static final String NE_POOL = NE_PKG_CLS + ".p"; - public static final String NE_ADD_W = NE_PKG_CLS + ".aw"; - public static final String NE_ADD_F = NE_PKG_CLS + ".af"; + public static final String TYPE_UTIL = "com.alibaba.testable.util.TypeUtil"; + public static final String CLASS_SUBSTITUTION = TYPE_UTIL + ".TestableSubstitution"; + public static final String METHOD_ADD_TO_CON_POLL = TYPE_UTIL + ".addToConstructorPool"; + public static final String METHOD_ADD_TO_MEM_POOL = TYPE_UTIL + ".addToMemberMethodPool"; public static final String TYPE_TO_CLASS = "class"; public static final String REF_THIS = "this"; public static final String VOID = "void"; diff --git a/core/src/main/java/com/alibaba/testable/util/TypeUtil.java b/core/src/main/java/com/alibaba/testable/util/TypeUtil.java index 2ffb089..ff28cce 100644 --- a/core/src/main/java/com/alibaba/testable/util/TypeUtil.java +++ b/core/src/main/java/com/alibaba/testable/util/TypeUtil.java @@ -2,16 +2,136 @@ package com.alibaba.testable.util; import java.lang.reflect.Constructor; import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +/** + * @author flin + */ public class TypeUtil { + /** + * Information of substitution method + */ + public static class TestableSubstitution { + public Class type; // target instance type to new / method return type + public Class[] parameterTypes; // constructor parameter types / member method parameter types + public Object targetObject; // object which provides substitution / object which provides substitution + public String methodName; // substitution method name / original member method name + + public TestableSubstitution(Class type, String methodName, Class[] parameterTypes, Object targetObject) { + this.type = type; + this.methodName = methodName; + this.parameterTypes = parameterTypes; + this.targetObject = targetObject; + } + } + + private static List mockNewPool = new ArrayList<>(); + private static List mockMemberPool = new ArrayList<>(); + + /** + * add item to constructor pool + */ + public static void addToConstructorPool(TestableSubstitution np) { + mockNewPool.add(np); + } + + /** + * add item to method pool + */ + public static void addToMemberMethodPool(TestableSubstitution np) { + mockMemberPool.add(np); + } + + /** + * substitution entry for new + */ + public static T wrapNew(Class ct, Object... as) { + Class[] cs = TypeUtil.getClassesFromObjects(as); + if (!mockNewPool.isEmpty()) { + try { + TestableSubstitution pi = getFromConstructorPool(ct, cs); + if (pi != null) { + Method m = pi.targetObject.getClass().getDeclaredMethod(pi.methodName, pi.parameterTypes); + m.setAccessible(true); + return (T)m.invoke(pi.targetObject, as); + } + } catch (Exception e) { + return null; + } + } + try { + Constructor c = TypeUtil.getConstructorByParameterTypes(ct.getConstructors(), cs); + if (c != null) { + return (T)c.newInstance(as); + } + } catch (Exception e) { + return null; + } + return null; + } + + /** + * substitution entry for member call + */ + public static T wrapCall(Object obj, String mn, Object... as) { + Class[] cs = TypeUtil.getClassesFromObjects(as); + if (!mockMemberPool.isEmpty()) { + try { + TestableSubstitution pi = getFromMemberMethodPool(mn, cs); + if (pi != null) { + Method m = pi.targetObject.getClass().getDeclaredMethod(pi.methodName, pi.parameterTypes); + m.setAccessible(true); + return (T)m.invoke(pi.targetObject, as); + } + } catch (Exception e) { + return null; + } + } + try { + Method m = TypeUtil.getMethodByNameAndParameterTypes(obj.getClass().getDeclaredMethods(), mn, cs); + if (m != null) { + m.setAccessible(true); + return (T)m.invoke(obj, as); + } + } catch (Exception e) { + return null; + } + return null; + } + + /** + * get from method pool by key + */ + private static TestableSubstitution getFromMemberMethodPool(String methodName, Class[] parameterTypes) { + for (TestableSubstitution f : mockMemberPool) { + if (f.methodName.equals(methodName) && TypeUtil.typeEquals(f.parameterTypes, parameterTypes)) { + return f; + } + } + return null; + } + + /** + * get from constructor pool by key + */ + private static TestableSubstitution getFromConstructorPool(Class type, Class[] parameterTypes) { + for (TestableSubstitution w : mockNewPool) { + if (w.type.equals(type) && TypeUtil.typeEquals(w.parameterTypes, parameterTypes)) { + return w; + } + } + return null; + } + /** * get classes of parameter objects */ - public static Class[] gcs(Object[] as) { - Class[] cs = new Class[as.length]; + public static Class[] getClassesFromObjects(Object[] parameterObjects) { + Class[] cs = new Class[parameterObjects.length]; for (int i = 0; i < cs.length; i++) { - cs[i] = as[i].getClass(); + cs[i] = parameterObjects[i].getClass(); } return cs; } @@ -19,9 +139,12 @@ public class TypeUtil { /** * get method by name and parameter matching */ - public static Method gm(Method[] mds, String mn, Class[] cs) { - for (Method m : mds) { - if (m.getName().equals(mn) && te(m.getParameterTypes(), cs)) { + public static Method getMethodByNameAndParameterTypes(Method[] availableMethods, + String methodName, + Class[] parameterTypes) { + for (Method m : availableMethods) { + if (m.getName().equals(methodName) && + typeEquals(m.getParameterTypes(), parameterTypes)) { return m; } } @@ -31,9 +154,10 @@ public class TypeUtil { /** * get constructor by parameter matching */ - public static Constructor gc(Constructor[] cons, Class[] cs) { - for (Constructor c : cons) { - if (te(c.getParameterTypes(), cs)) { + public static Constructor getConstructorByParameterTypes(Constructor[] constructors, + Class[] parameterTypes) { + for (Constructor c : constructors) { + if (typeEquals(c.getParameterTypes(), parameterTypes)) { return c; } } @@ -43,12 +167,13 @@ public class TypeUtil { /** * type equeals */ - public static boolean te(Class[] c1, Class[] c2) { - if (c1.length != c2.length) { + public static boolean typeEquals(Class[] classesLeft, Class[] classesRight) { + if (classesLeft.length != classesRight.length) { return false; } - for (int i = 0; i < c1.length; i++) { - if (!c1[i].equals(c2[i]) && !fe(c1[i], c2[i])) { + for (int i = 0; i < classesLeft.length; i++) { + if (!classesLeft[i].equals(classesRight[i]) && + !fuzzyEqual(classesLeft[i], classesRight[i])) { return false; } } @@ -57,18 +182,18 @@ public class TypeUtil { /** * fuzzy equal - * @param c1 fact types (can be primary type) - * @param c2 user types + * @param factTypes fact types (can be primary type) + * @param userTypes user types */ - private static boolean fe(Class c1, Class c2) { - return (c1.equals(int.class) && c2.equals(Integer.class)) || - (c1.equals(long.class) && c2.equals(Long.class)) || - (c1.equals(short.class) && c2.equals(Short.class)) || - (c1.equals(boolean.class) && c2.equals(Boolean.class)) || - (c1.equals(char.class) && c2.equals(Character.class)) || - (c1.equals(byte.class) && c2.equals(Byte.class)) || - (c1.equals(float.class) && c2.equals(Float.class)) || - (c1.equals(double.class) && c2.equals(Double.class)); + private static boolean fuzzyEqual(Class factTypes, Class userTypes) { + return (factTypes.equals(int.class) && userTypes.equals(Integer.class)) || + (factTypes.equals(long.class) && userTypes.equals(Long.class)) || + (factTypes.equals(short.class) && userTypes.equals(Short.class)) || + (factTypes.equals(boolean.class) && userTypes.equals(Boolean.class)) || + (factTypes.equals(char.class) && userTypes.equals(Character.class)) || + (factTypes.equals(byte.class) && userTypes.equals(Byte.class)) || + (factTypes.equals(float.class) && userTypes.equals(Float.class)) || + (factTypes.equals(double.class) && userTypes.equals(Double.class)); } } diff --git a/core/src/main/java/n/e.java b/core/src/main/java/n/e.java new file mode 100644 index 0000000..90bafff --- /dev/null +++ b/core/src/main/java/n/e.java @@ -0,0 +1,64 @@ +package n; + +import static com.alibaba.testable.util.TypeUtil.wrapNew; + +public final class e { + + public static T w(Class ct) { + return wrapNew(ct); + } + + public static T w(Class ct, Object a1) { + return wrapNew(ct, a1); + } + + public static T w(Class ct, Object a1, Object a2) { + return wrapNew(ct, a1, a2); + } + + public static T w(Class ct, Object a1, Object a2, Object a3) { + return wrapNew(ct, a1, a2, a3); + } + + public static T w(Class ct, Object a1, Object a2, Object a3, Object a4) { + return wrapNew(ct, a1, a2, a3, a4); + } + + public static T w(Class ct, Object a1, Object a2, Object a3, Object a4, Object a5) { + return wrapNew(ct, a1, a2, a3, a4, a5); + } + + public static T w(Class ct, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { + return wrapNew(ct, a1, a2, a3, a4, a5, a6); + } + + public static T w(Class ct, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { + return wrapNew(ct, a1, a2, a3, a4, a5, a6, a7); + } + + public static T w(Class ct, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, + Object a8) { + return wrapNew(ct, a1, a2, a3, a4, a5, a6, a7, a8); + } + + public static T w(Class ct, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) { + return wrapNew(ct, a1, a2, a3, a4, a5, a6, a7, a8, a9); + } + + public static T w(Class ct, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10) { + return wrapNew(ct, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); + } + + public static T w(Class ct, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11) { + return wrapNew(ct, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); + } + + public static T w(Class ct, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9, Object a10, Object a11, Object a12) { + return wrapNew(ct, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12); + } + +} diff --git a/core/src/main/java/testable_internal/n/e.java b/core/src/main/java/testable_internal/n/e.java deleted file mode 100644 index 397e825..0000000 --- a/core/src/main/java/testable_internal/n/e.java +++ /dev/null @@ -1,182 +0,0 @@ -package testable_internal.n; - -import com.alibaba.testable.util.TypeUtil; - -import java.lang.Class; -import java.lang.Object; -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; -import java.util.*; - -public final class e { - - public static class p { - public Class c; // target instance type to new / method return type - public Class[] a; // constructor parameter types / member method parameter types - public Object o; // object which provides substitution / object which provides substitution - public String m; // substitutional method name / original member method name - - public p(Class c, String m, Class[] a, Object o) { - this.c = c; - this.m = m; - this.a = a; - this.o = o; - } - } - - private static List

pw = new ArrayList<>(); - private static List

pf = new ArrayList<>(); - - /** - * add item to constructor pool - */ - public static void aw(p np) { - pw.add(np); - } - - /** - * add item to method pool - */ - public static void af(p np) { - pf.add(np); - } - - public static T w(Class ct) { - return wi(ct); - } - - public static T w(Class ct, Object a1) { - return wi(ct, a1); - } - - public static T w(Class ct, Object a1, Object a2) { - return wi(ct, a1, a2); - } - - public static T w(Class ct, Object a1, Object a2, Object a3) { - return wi(ct, a1, a2, a3); - } - - public static T w(Class ct, Object a1, Object a2, Object a3, Object a4) { - return wi(ct, a1, a2, a3, a4); - } - - public static T w(Class ct, Object a1, Object a2, Object a3, Object a4, Object a5) { - return wi(ct, a1, a2, a3, a4, a5); - } - - public static T w(Class ct, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) { - return wi(ct, a1, a2, a3, a4, a5, a6); - } - - public static T w(Class ct, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { - return wi(ct, a1, a2, a3, a4, a5, a6, a7); - } - - public static T w(Class ct, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, - Object a8) { - return wi(ct, a1, a2, a3, a4, a5, a6, a7, a8); - } - - public static T w(Class ct, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, - Object a8, Object a9) { - return wi(ct, a1, a2, a3, a4, a5, a6, a7, a8, a9); - } - - public static T w(Class ct, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, - Object a8, Object a9, Object a10) { - return wi(ct, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); - } - - public static T w(Class ct, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, - Object a8, Object a9, Object a10, Object a11) { - return wi(ct, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); - } - - public static T w(Class ct, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, - Object a8, Object a9, Object a10, Object a11, Object a12) { - return wi(ct, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12); - } - - /** - * substitution entry for new - */ - public static T wi(Class ct, Object... as) { - Class[] cs = TypeUtil.gcs(as); - if (!pw.isEmpty()) { - try { - p pi = gpw(ct, cs); - if (pi != null) { - Method m = pi.o.getClass().getDeclaredMethod(pi.m, pi.a); - m.setAccessible(true); - return (T)m.invoke(pi.o, as); - } - } catch (Exception e) { - return null; - } - } - try { - Constructor c = TypeUtil.gc(ct.getConstructors(), cs); - if (c != null) { - return (T)c.newInstance(as); - } - } catch (Exception e) { - return null; - } - return null; - } - - /** - * substitution entry for member call - */ - public static T f(Object obj, String mn, Object... as) { - Class[] cs = TypeUtil.gcs(as); - if (!pf.isEmpty()) { - try { - p pi = gpf(mn, cs); - if (pi != null) { - Method m = pi.o.getClass().getDeclaredMethod(pi.m, pi.a); - m.setAccessible(true); - return (T)m.invoke(pi.o, as); - } - } catch (Exception e) { - return null; - } - } - try { - Method m = TypeUtil.gm(obj.getClass().getDeclaredMethods(), mn, cs); - if (m != null) { - m.setAccessible(true); - return (T)m.invoke(obj, as); - } - } catch (Exception e) { - return null; - } - return null; - } - - /** - * get from method pool by key - */ - private static p gpf(String mn, Class[] cs) { - for (p f : pf) { - if (f.m.equals(mn) && TypeUtil.te(f.a, cs)) { - return f; - } - } - return null; - } - - /** - * get from constructor pool by key - */ - private static p gpw(Class ct, Class[] cs) { - for (p w : pw) { - if (w.c.equals(ct) && TypeUtil.te(w.a, cs)) { - return w; - } - } - return null; - } - -}