refactor n.e class to type util

This commit is contained in:
金戟 2020-07-22 22:09:03 +08:00
parent f30e8ffd3a
commit d91d972aa7
7 changed files with 224 additions and 217 deletions

View File

@ -20,7 +20,7 @@ import static com.alibaba.testable.constant.Const.SYS_CLASSES;
public class TestableClassTransformer implements Opcodes {
private static final String CONSTRUCTOR = "<init>";
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 {

View File

@ -33,8 +33,8 @@ public class PrivateAccessor {
public static <T> 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) {

View File

@ -50,9 +50,9 @@ public class TestSetupMethodGenerator extends BaseGenerator {
ListBuffer<JCStatement> statements = new ListBuffer<>();
for (Pair<Name, Pair<JCExpression, List<JCExpression>>> 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<Name, Pair<JCExpression, List<JCExpression>>> 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)),

View File

@ -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";

View File

@ -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<TestableSubstitution> mockNewPool = new ArrayList<>();
private static List<TestableSubstitution> 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> T wrapNew(Class<T> 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> 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));
}
}

View File

@ -0,0 +1,64 @@
package n;
import static com.alibaba.testable.util.TypeUtil.wrapNew;
public final class e {
public static <T> T w(Class<T> ct) {
return wrapNew(ct);
}
public static <T> T w(Class<T> ct, Object a1) {
return wrapNew(ct, a1);
}
public static <T> T w(Class<T> ct, Object a1, Object a2) {
return wrapNew(ct, a1, a2);
}
public static <T> T w(Class<T> ct, Object a1, Object a2, Object a3) {
return wrapNew(ct, a1, a2, a3);
}
public static <T> T w(Class<T> ct, Object a1, Object a2, Object a3, Object a4) {
return wrapNew(ct, a1, a2, a3, a4);
}
public static <T> T w(Class<T> ct, Object a1, Object a2, Object a3, Object a4, Object a5) {
return wrapNew(ct, a1, a2, a3, a4, a5);
}
public static <T> T w(Class<T> 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> T w(Class<T> 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> T w(Class<T> 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> T w(Class<T> 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> T w(Class<T> 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> T w(Class<T> 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> T w(Class<T> 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);
}
}

View File

@ -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<p> pw = new ArrayList<>();
private static List<p> 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> T w(Class<T> ct) {
return wi(ct);
}
public static <T> T w(Class<T> ct, Object a1) {
return wi(ct, a1);
}
public static <T> T w(Class<T> ct, Object a1, Object a2) {
return wi(ct, a1, a2);
}
public static <T> T w(Class<T> ct, Object a1, Object a2, Object a3) {
return wi(ct, a1, a2, a3);
}
public static <T> T w(Class<T> ct, Object a1, Object a2, Object a3, Object a4) {
return wi(ct, a1, a2, a3, a4);
}
public static <T> T w(Class<T> ct, Object a1, Object a2, Object a3, Object a4, Object a5) {
return wi(ct, a1, a2, a3, a4, a5);
}
public static <T> T w(Class<T> 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> T w(Class<T> 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> T w(Class<T> 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> T w(Class<T> 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> T w(Class<T> 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> T w(Class<T> 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> T w(Class<T> 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> T wi(Class<T> 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> 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;
}
}