diff --git a/src/main/java/com/alibaba/testable/generator/TestableClassDevRoleGenerator.java b/src/main/java/com/alibaba/testable/generator/TestableClassDevRoleGenerator.java index 26bc54a..ad82e57 100644 --- a/src/main/java/com/alibaba/testable/generator/TestableClassDevRoleGenerator.java +++ b/src/main/java/com/alibaba/testable/generator/TestableClassDevRoleGenerator.java @@ -5,7 +5,6 @@ import com.alibaba.testable.generator.statement.CallSuperMethodStatementGenerato import com.alibaba.testable.model.TestableContext; import com.alibaba.testable.translator.TestableClassDevRoleTranslator; import com.alibaba.testable.util.ConstPool; -import com.alibaba.testable.util.StringUtil; import com.squareup.javapoet.*; import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.code.Type; @@ -52,7 +51,6 @@ public class TestableClassDevRoleGenerator { methodSpecs.add(buildFieldGetter(clazz, field)); methodSpecs.add(buildFieldSetter(clazz, field)); } - methodSpecs.add(buildStubbornFieldMethod(translator.getFields())); TypeSpec.Builder builder = TypeSpec.classBuilder(className) .addModifiers(Modifier.PUBLIC, Modifier.FINAL) @@ -65,18 +63,6 @@ public class TestableClassDevRoleGenerator { return javaFile.toString(); } - private MethodSpec buildStubbornFieldMethod(List fields) { - List fieldNames = new ArrayList<>(); - for (JCTree.JCVariableDecl f : fields) { - fieldNames.add("\"" + f.name.toString() + "\""); - } - return MethodSpec.methodBuilder(ConstPool.STUBBORN_FIELD_METHOD) - .addModifiers(Modifier.PUBLIC).addModifiers(Modifier.STATIC) - .addStatement("return new $T[]{" + StringUtil.join(fieldNames, ",") + "}", String.class) - .returns(ArrayTypeName.of(String.class)) - .build(); - } - private MethodSpec buildFieldGetter(Symbol.ClassSymbol classElement, JCTree.JCVariableDecl field) { String fieldName = field.name.toString(); return MethodSpec.methodBuilder(fieldName + ConstPool.TESTABLE_GET_METHOD_PREFIX) diff --git a/src/main/java/com/alibaba/testable/processor/TestableProcessor.java b/src/main/java/com/alibaba/testable/processor/TestableProcessor.java index 0c910db..ea00d7a 100644 --- a/src/main/java/com/alibaba/testable/processor/TestableProcessor.java +++ b/src/main/java/com/alibaba/testable/processor/TestableProcessor.java @@ -53,7 +53,7 @@ public class TestableProcessor extends BaseProcessor { private void createStaticNewClass() { if (!isStaticNewClassExist()) { try { - writeSourceFile(ConstPool.SN_PKG_CLS, new StaticNewClassGenerator(cx).fetch()); + writeSourceFile(ConstPool.NE_PKG_CLS, new StaticNewClassGenerator(cx).fetch()); } catch (IOException e) { e.printStackTrace(); } @@ -62,8 +62,8 @@ public class TestableProcessor extends BaseProcessor { private boolean isStaticNewClassExist() { try { - FileObject staticNewClassFile = cx.filter.getResource(SOURCE_OUTPUT, ConstPool.SN_PKG, - ConstPool.SN_CLS + JAVA_POSTFIX); + FileObject staticNewClassFile = cx.filter.getResource(SOURCE_OUTPUT, ConstPool.NE_PKG, + ConstPool.NE_CLS + JAVA_POSTFIX); return isCompilingTestClass(staticNewClassFile) || staticNewClassFile.getLastModified() > 0; } catch (FilerException e) { return true; diff --git a/src/main/java/com/alibaba/testable/translator/TestableClassDevRoleTranslator.java b/src/main/java/com/alibaba/testable/translator/TestableClassDevRoleTranslator.java index 432a41f..51f3747 100644 --- a/src/main/java/com/alibaba/testable/translator/TestableClassDevRoleTranslator.java +++ b/src/main/java/com/alibaba/testable/translator/TestableClassDevRoleTranslator.java @@ -1,8 +1,6 @@ package com.alibaba.testable.translator; import com.alibaba.testable.model.TestableContext; -import com.alibaba.testable.translator.tree.TestableFieldAccess; -import com.alibaba.testable.translator.tree.TestableMethodInvocation; import com.alibaba.testable.util.ConstPool; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCMethodDecl; @@ -11,8 +9,6 @@ import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Name; -import java.lang.reflect.Modifier; - /** * Travel AST * @@ -44,12 +40,6 @@ public class TestableClassDevRoleTranslator extends TreeTranslator { this.cx = cx; } - @Override - public void visitClassDef(JCTree.JCClassDecl jcClassDecl) { - super.visitClassDef(jcClassDecl); - jcClassDecl.mods.flags = jcClassDecl.mods.flags & (~Modifier.FINAL); - } - /** * Record all methods */ @@ -61,46 +51,60 @@ public class TestableClassDevRoleTranslator extends TreeTranslator { /** * Case: new Demo() + * Case: member() */ @Override public void visitExec(JCTree.JCExpressionStatement jcExpressionStatement) { - jcExpressionStatement.expr = checkAndExchangeNewOperation(jcExpressionStatement.expr); + jcExpressionStatement.expr = checkAndExchange(jcExpressionStatement.expr); super.visitExec(jcExpressionStatement); } /** + * For member method invocation break point * Case: call(new Demo()) */ @Override public void visitApply(JCTree.JCMethodInvocation tree) { - tree.args = checkAndExchangeNewOperation(tree.args); + tree.args = checkAndExchange(tree.args); super.visitApply(tree); } + /** + * Case: return new Demo() + * Case: return member() + */ + @Override + public void visitReturn(JCTree.JCReturn jcReturn) { + jcReturn.expr = checkAndExchange(jcReturn.expr); + super.visitReturn(jcReturn); + } + /** * Record all private fields * Case: Demo d = new Demo() + * Case: Demo d = member() */ @Override public void visitVarDef(JCTree.JCVariableDecl jcVariableDecl) { if (isStubbornField(jcVariableDecl.mods)) { fields = fields.append(jcVariableDecl); } - jcVariableDecl.init = checkAndExchangeNewOperation(jcVariableDecl.init); + jcVariableDecl.init = checkAndExchange(jcVariableDecl.init); super.visitVarDef(jcVariableDecl); } /** * Case: new Demo().call() + * Case: member().call() */ @Override public void visitSelect(JCTree.JCFieldAccess jcFieldAccess) { - jcFieldAccess.selected = checkAndExchangeNewOperation(jcFieldAccess.selected); + jcFieldAccess.selected = checkAndExchange(jcFieldAccess.selected); super.visitSelect(jcFieldAccess); } /** - * For break point + * For new operation break point */ @Override public void visitNewClass(JCTree.JCNewClass jcNewClass) { @@ -108,7 +112,7 @@ public class TestableClassDevRoleTranslator extends TreeTranslator { } /** - * For break point + * For new operation break point */ @Override public void visitNewArray(JCTree.JCNewArray jcNewArray) { @@ -120,43 +124,62 @@ public class TestableClassDevRoleTranslator extends TreeTranslator { mods.getFlags().contains(javax.lang.model.element.Modifier.FINAL); } - private List checkAndExchangeNewOperation(List args) { + private List checkAndExchange(List args) { if (args != null) { JCTree.JCExpression[] es = new JCTree.JCExpression[args.length()]; for (int i = 0; i < args.length(); i++) { - es[i] = checkAndExchangeNewOperation(args.get(i)); + es[i] = checkAndExchange(args.get(i)); } return List.from(es); } return null; } - private JCTree.JCExpression checkAndExchangeNewOperation(JCTree.JCExpression expr) { + private JCTree.JCExpression checkAndExchange(JCTree.JCExpression expr) { if (isNewOperation(expr)) { JCTree.JCNewClass newClassExpr = (JCTree.JCNewClass)expr; Name className = ((JCTree.JCIdent)newClassExpr.clazz).name; try { - return getStaticNewCall(newClassExpr, className); + return getGlobalNewInvocation(newClassExpr, className); } catch (Exception e) { e.printStackTrace(); } + } else if (isMemberMethodInvocation(expr)) { + Name methodName = ((JCTree.JCIdent)((JCTree.JCMethodInvocation)expr).meth).name; + List args = ((JCTree.JCMethodInvocation)expr).args; + return getGlobalMemberInvocation(methodName, args); } return expr; } + private boolean isMemberMethodInvocation(JCTree.JCExpression expr) { + return expr != null && expr.getClass().equals(JCTree.JCMethodInvocation.class) && + ((JCTree.JCMethodInvocation)expr).meth.getClass().equals(JCTree.JCIdent.class); + } + private boolean isNewOperation(JCTree.JCExpression expr) { return expr != null && expr.getClass().equals(JCTree.JCNewClass.class); } - private TestableMethodInvocation getStaticNewCall(JCTree.JCNewClass newClassExpr, Name className) { - TestableFieldAccess snClass = new TestableFieldAccess(cx.treeMaker.Ident(cx.names.fromString(ConstPool.SN_PKG)), - cx.names.fromString(ConstPool.SN_CLS), null); - TestableFieldAccess snMethod = new TestableFieldAccess(snClass, - cx.names.fromString(ConstPool.SN_METHOD), null); - JCTree.JCExpression classType = new TestableFieldAccess(cx.treeMaker.Ident(className), - cx.names.fromString(ConstPool.TYPE_TO_CLASS), null); + private JCTree.JCMethodInvocation getGlobalNewInvocation(JCTree.JCNewClass newClassExpr, Name className) { + JCTree.JCFieldAccess snClass = cx.treeMaker.Select(cx.treeMaker.Ident(cx.names.fromString(ConstPool.NE_PKG)), + cx.names.fromString(ConstPool.NE_CLS)); + JCTree.JCFieldAccess snMethod = cx.treeMaker.Select(snClass, cx.names.fromString(ConstPool.NE_NEW)); + JCTree.JCExpression classType = cx.treeMaker.Select(cx.treeMaker.Ident(className), + cx.names.fromString(ConstPool.TYPE_TO_CLASS)); ListBuffer args = ListBuffer.of(classType); args.addAll(newClassExpr.args); - return new TestableMethodInvocation(null, snMethod, args.toList()); + return cx.treeMaker.Apply(List.nil(), snMethod, args.toList()); + } + + private JCTree.JCMethodInvocation getGlobalMemberInvocation(Name methodName, List param) { + JCTree.JCFieldAccess snClass = cx.treeMaker.Select(cx.treeMaker.Ident(cx.names.fromString(ConstPool.NE_PKG)), + cx.names.fromString(ConstPool.NE_CLS)); + JCTree.JCFieldAccess snMethod = cx.treeMaker.Select(snClass, cx.names.fromString(ConstPool.NE_INK)); + ListBuffer args = new ListBuffer(); + args.add(cx.treeMaker.Ident(cx.names.fromString(ConstPool.REF_THIS))); + args.add(cx.treeMaker.Literal(methodName.toString())); + args.addAll(param); + return cx.treeMaker.Apply(List.nil(), snMethod, args.toList()); } } diff --git a/src/main/java/com/alibaba/testable/translator/TestableClassTestRoleTranslator.java b/src/main/java/com/alibaba/testable/translator/TestableClassTestRoleTranslator.java index e0b678b..182e522 100644 --- a/src/main/java/com/alibaba/testable/translator/TestableClassTestRoleTranslator.java +++ b/src/main/java/com/alibaba/testable/translator/TestableClassTestRoleTranslator.java @@ -2,8 +2,6 @@ package com.alibaba.testable.translator; import com.alibaba.testable.model.TestLibType; import com.alibaba.testable.model.TestableContext; -import com.alibaba.testable.translator.tree.TestableFieldAccess; -import com.alibaba.testable.translator.tree.TestableMethodInvocation; import com.alibaba.testable.util.ConstPool; import com.sun.tools.javac.code.Type; import com.sun.tools.javac.tree.JCTree; @@ -27,11 +25,11 @@ public class TestableClassTestRoleTranslator extends TreeTranslator { private static final String ANNOTATION_JUNIT5_SETUP = "org.junit.jupiter.api.BeforeEach"; private static final String ANNOTATION_JUNIT5_TEST = "org.junit.jupiter.api.Test"; private static final String TYPE_CLASS = "Class"; - private static final String REF_THIS = "this"; private final TestableContext cx; private String sourceClassName = ""; - private ListBuffer sourceClassIns = new ListBuffer(); - private List stubbornFields = List.nil(); + private final ListBuffer sourceClassIns = new ListBuffer(); + private final ListBuffer stubbornFields = new ListBuffer(); + private final ListBuffer memberMethods = new ListBuffer(); /** * MethodName -> (ResultType -> ParameterTypes) @@ -44,10 +42,14 @@ public class TestableClassTestRoleTranslator extends TreeTranslator { this.sourceClassName = className; this.cx = cx; try { - stubbornFields = List.from( - (String[])Class.forName(pkgName + "." + className + ConstPool.TESTABLE) - .getMethod(ConstPool.STUBBORN_FIELD_METHOD) - .invoke(null)); + Class cls = Class.forName(pkgName + "." + className); + Field[] fields = cls.getDeclaredFields(); + for (Field f : fields) { + if (Modifier.isFinal(f.getModifiers()) || Modifier.isPrivate(f.getModifiers())) { + stubbornFields.add(f.getName()); + } + } + memberMethods.addAll(Arrays.asList(cls.getDeclaredMethods())); } catch (Exception e) { e.printStackTrace(); } @@ -85,10 +87,9 @@ public class TestableClassTestRoleTranslator extends TreeTranslator { if (jcExpressionStatement.expr.getClass().equals(JCAssign.class) && isAssignStubbornField((JCAssign)jcExpressionStatement.expr)) { JCAssign assign = (JCAssign)jcExpressionStatement.expr; - // TODO: Use treeMaker.Apply() and treeMaker.Select() - TestableFieldAccess stubbornSetter = new TestableFieldAccess(((JCFieldAccess)assign.lhs).selected, - getStubbornSetterMethodName(assign), null); - jcExpressionStatement.expr = new TestableMethodInvocation(null, stubbornSetter, + JCFieldAccess stubbornSetter = cx.treeMaker.Select(((JCFieldAccess)assign.lhs).selected, + getStubbornSetterMethodName(assign)); + jcExpressionStatement.expr = cx.treeMaker.Apply(List.nil(), stubbornSetter, com.sun.tools.javac.util.List.of(assign.rhs)); } super.visitExec(jcExpressionStatement); @@ -103,12 +104,14 @@ public class TestableClassTestRoleTranslator extends TreeTranslator { for (JCVariableDecl p : jcMethodDecl.params) { args.add(cx.treeMaker.Select(p.vartype, cx.names.fromString(ConstPool.TYPE_TO_CLASS))); } - JCExpression retType = cx.treeMaker.Select(jcMethodDecl.restype, cx.names.fromString(ConstPool.TYPE_TO_CLASS)); + JCExpression retType = jcMethodDecl.restype == null ? null : + cx.treeMaker.Select(jcMethodDecl.restype, cx.names.fromString(ConstPool.TYPE_TO_CLASS)); injectMethods.add(Pair.of(jcMethodDecl.name, Pair.of(retType, args.toList()))); break; case ANNOTATION_JUNIT5_SETUP: testSetupMethodName = jcMethodDecl.name.toString(); - jcMethodDecl.mods.annotations = removeAnnotation(jcMethodDecl.mods.annotations, ANNOTATION_JUNIT5_SETUP); + jcMethodDecl.mods.annotations = removeAnnotation(jcMethodDecl.mods.annotations, + ANNOTATION_JUNIT5_SETUP); break; case ANNOTATION_JUNIT5_TEST: testLibType = TestLibType.JUnit5; @@ -155,7 +158,7 @@ public class TestableClassTestRoleTranslator extends TreeTranslator { private JCExpression nameToExpression(String dotName) { String[] nameParts = dotName.split("\\."); JCExpression e = cx.treeMaker.Ident(cx.names.fromString(nameParts[0])); - for (int i = 1 ; i < nameParts.length ; i++) { + for (int i = 1; i < nameParts.length; i++) { e = cx.treeMaker.Select(e, cx.names.fromString(nameParts[i])); } return e; @@ -164,7 +167,11 @@ public class TestableClassTestRoleTranslator extends TreeTranslator { private JCBlock testableSetupBlock() { ListBuffer statements = new ListBuffer<>(); for (Pair>> m : injectMethods.toList()) { - statements.append(toGlobalNewStatement(m)); + if (isMemberMethod(m)) { + statements.append(toGlobalInvokeStatement(m)); + } else { + statements.append(toGlobalNewStatement(m)); + } } if (!testSetupMethodName.isEmpty()) { statements.append(cx.treeMaker.Exec(cx.treeMaker.Apply(List.nil(), @@ -173,20 +180,59 @@ public class TestableClassTestRoleTranslator extends TreeTranslator { return cx.treeMaker.Block(0, statements.toList()); } - private JCStatement toGlobalNewStatement( - Pair>> m) { - JCExpression key = nameToExpression(ConstPool.NS_W_KEY); - JCExpression classType = m.snd.fst; + private boolean isMemberMethod(Pair>> m) { + for (Method method : memberMethods) { + if (method.getName().equals(m.fst.toString()) && parameterEquals(m.snd.snd, method.getParameterTypes())) { + return true; + } + } + return false; + } + + private boolean parameterEquals(List injectMethodArgs, Class[] memberMethodArgs) { + if (injectMethodArgs.length() != memberMethodArgs.length) { + return false; + } + for (int i = 0; i < injectMethodArgs.length(); i++) { + if (!memberMethodArgs[i].getName().equals(((JCFieldAccess)injectMethodArgs.get(i)).selected.type + .toString())) { + return false; + } + } + return true; + } + + private JCStatement toGlobalInvokeStatement(Pair>> m) { + JCExpression key = nameToExpression(ConstPool.NE_X_KEY); + JCExpression value = nameToExpression(ConstPool.NE_X_VAL); + JCExpression methodName = cx.treeMaker.Literal(m.fst.toString()); + JCExpression thisIns = cx.treeMaker.Ident(cx.names.fromString(ConstPool.REF_THIS)); + JCExpression returnClassType = m.snd.fst; JCExpression parameterTypes = cx.treeMaker.NewArray(cx.treeMaker.Ident(cx.names.fromString(TYPE_CLASS)), List.nil(), m.snd.snd); JCNewClass keyClass = cx.treeMaker.NewClass(null, List.nil(), key, - List.of(classType, parameterTypes), null); - JCExpression value = nameToExpression(ConstPool.NS_VAL); - JCExpression thisIns = cx.treeMaker.Ident(cx.names.fromString(REF_THIS)); + List.of(methodName, parameterTypes), null); + JCNewClass valClass = cx.treeMaker.NewClass(null, List.nil(), value, + List.of(thisIns, returnClassType), null); + JCExpression addInjectMethod = nameToExpression(ConstPool.NE_X_ADD); + JCMethodInvocation apply = cx.treeMaker.Apply(List.nil(), addInjectMethod, + List.from(new JCExpression[] {keyClass, valClass})); + return cx.treeMaker.Exec(apply); + } + + private JCStatement toGlobalNewStatement(Pair>> m) { + JCExpression key = nameToExpression(ConstPool.NE_W_KEY); + JCExpression value = nameToExpression(ConstPool.NE_W_VAL); + JCExpression classType = m.snd.fst; + JCExpression parameterTypes = cx.treeMaker.NewArray(cx.treeMaker.Ident(cx.names.fromString(TYPE_CLASS)), + List.nil(), m.snd.snd); + JCExpression thisIns = cx.treeMaker.Ident(cx.names.fromString(ConstPool.REF_THIS)); JCExpression methodName = cx.treeMaker.Literal(m.fst.toString()); + JCNewClass keyClass = cx.treeMaker.NewClass(null, List.nil(), key, + List.of(classType, parameterTypes), null); JCNewClass valClass = cx.treeMaker.NewClass(null, List.nil(), value, List.of(thisIns, methodName), null); - JCExpression addInjectMethod = nameToExpression(ConstPool.NS_W_ADD); + JCExpression addInjectMethod = nameToExpression(ConstPool.NE_W_ADD); JCMethodInvocation apply = cx.treeMaker.Apply(List.nil(), addInjectMethod, List.from(new JCExpression[] {keyClass, valClass})); return cx.treeMaker.Exec(apply); diff --git a/src/main/java/com/alibaba/testable/translator/tree/TestableFieldAccess.java b/src/main/java/com/alibaba/testable/translator/tree/TestableFieldAccess.java deleted file mode 100644 index 6acc56d..0000000 --- a/src/main/java/com/alibaba/testable/translator/tree/TestableFieldAccess.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.alibaba.testable.translator.tree; - -import com.sun.tools.javac.code.Symbol; -import com.sun.tools.javac.tree.JCTree; -import com.sun.tools.javac.util.Name; - -/** - * @author flin - */ -public class TestableFieldAccess extends JCTree.JCFieldAccess { - - public TestableFieldAccess(JCExpression selected, Name name, Symbol sym) { - super(selected, name, sym); - } - -} diff --git a/src/main/java/com/alibaba/testable/translator/tree/TestableMethodInvocation.java b/src/main/java/com/alibaba/testable/translator/tree/TestableMethodInvocation.java deleted file mode 100644 index fd7a452..0000000 --- a/src/main/java/com/alibaba/testable/translator/tree/TestableMethodInvocation.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.alibaba.testable.translator.tree; - -import com.sun.tools.javac.tree.JCTree; -import com.sun.tools.javac.util.List; - -/** - * @author flin - */ -public class TestableMethodInvocation extends JCTree.JCMethodInvocation { - - public TestableMethodInvocation(List typeargs, JCExpression meth, List args) { - super(typeargs, meth, args); - } - -} diff --git a/src/main/java/com/alibaba/testable/util/ConstPool.java b/src/main/java/com/alibaba/testable/util/ConstPool.java index bdcc779..c280694 100644 --- a/src/main/java/com/alibaba/testable/util/ConstPool.java +++ b/src/main/java/com/alibaba/testable/util/ConstPool.java @@ -8,16 +8,20 @@ public final class ConstPool { public static final String CONSTRUCTOR_NAME = ""; public static final String TYPE_VOID = "void"; public static final String TESTABLE = "Testable"; - public static final String SN_PKG = "n"; - public static final String SN_CLS = "e"; - public static final String SN_METHOD = "w"; - public static final String SN_PKG_CLS = "n.e"; - public static final String NS_W_KEY = "n.e.wk"; - public static final String NS_VAL = "n.e.v"; - public static final String NS_W_ADD = "n.e.wa"; - public static final String STUBBORN_FIELD_METHOD = "stubbornField"; + 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_INK = "x"; + public static final String NE_PKG_CLS = "n.e"; + public static final String NE_W_KEY = "n.e.wk"; + public static final String NE_X_KEY = "n.e.xk"; + public static final String NE_W_VAL = "n.e.wv"; + public static final String NE_X_VAL = "n.e.xv"; + public static final String NE_W_ADD = "n.e.wa"; + public static final String NE_X_ADD = "n.e.xa"; public static final String TESTABLE_GET_METHOD_PREFIX = "TestableGet"; public static final String TESTABLE_SET_METHOD_PREFIX = "TestableSet"; public static final String TYPE_TO_CLASS = "class"; + public static final String REF_THIS = "this"; } diff --git a/src/main/resources/e.java b/src/main/resources/e.java index 4e5d4b6..2e79927 100644 --- a/src/main/resources/e.java +++ b/src/main/resources/e.java @@ -57,33 +57,46 @@ public final class e { } /** - * value for contructor and method pool + * value for contructor pool */ - public static class v { + public static class wv { public Object o; // object which provides substitution public String m; // substitutional method name - public v(Object o, String m) { + public wv(Object o, String m) { this.o = o; this.m = m; } } - private static Map wp = new HashMap<>(); - private static Map xp = new HashMap<>(); + /** + * value for member method pool + */ + public static class xv { + public Object o; // object which provides substitution + public Class c; // method return type + + public xv(Object o, Class c) { + this.o = o; + this.c = c; + } + } + + private static Map wp = new HashMap<>(); + private static Map xp = new HashMap<>(); /** * add item to contructor pool */ - public static void wa(wk k, v vv) { - wp.put(k, vv); + public static void wa(wk k, wv v) { + wp.put(k, v); } /** * add item to method pool */ - public static void xa(xk k, v vv) { - xp.put(k, vv); + public static void xa(xk k, xv v) { + xp.put(k, v); } /** @@ -96,7 +109,7 @@ public final class e { } if (!wp.isEmpty()) { try { - Pair p = gwp(new wk(ct, cs)); + Pair p = gwp(new wk(ct, cs)); if (p != null) { Method m = p.snd.o.getClass().getDeclaredMethod(p.snd.m, p.fst.a); m.setAccessible(true); @@ -120,24 +133,25 @@ public final class e { /** * subsitituion entry for member call */ - public static Object x(Object obj, String method, Object... as) { + public static T x(Object obj, String method, Object... as) { Class[] cs = gcs(as); if (!xp.isEmpty()) { try { - Pair p = gxp(new xk(method, cs)); + Pair p = gxp(new xk(method, cs)); if (p != null) { - Method m = p.snd.o.getClass().getDeclaredMethod(p.snd.m, p.fst.a); + Method m = p.snd.o.getClass().getDeclaredMethod(p.fst.m, p.fst.a); m.setAccessible(true); - return m.invoke(p.snd.o, as); + return (T)m.invoke(p.snd.o, as); } } catch (Exception e) { return null; } } try { - Method m = gm(obj.getClass().getMethods(), cs); + Method m = gm(obj.getClass().getDeclaredMethods(), method, cs); if (m != null) { - return m.invoke(obj, as); + m.setAccessible(true); + return (T)m.invoke(obj, as); } } catch (Exception e) { return null; @@ -159,9 +173,9 @@ public final class e { /** * get method by parameter matching */ - private static Method gm(Method[] methods, Class[] cs) { + private static Method gm(Method[] methods, String name, Class[] cs) { for (Method m : methods) { - if (te(m.getParameterTypes(), cs)) { + if (m.getName().equals(name) && te(m.getParameterTypes(), cs)) { return m; } } @@ -171,7 +185,7 @@ public final class e { /** * get from method pool by key */ - private static Pair gxp(xk k1) { + private static Pair gxp(xk k1) { for (xk k2 : xp.keySet()) { if (k1.m.equals(k2.m) && te(k2.a, k1.a)) { return Pair.of(k2, xp.get(k2)); @@ -195,7 +209,7 @@ public final class e { /** * get from contructor pool by key */ - private static Pair gwp(wk k1) { + private static Pair gwp(wk k1) { for (wk k2 : wp.keySet()) { if (k1.c.equals(k2.c) && te(k2.a, k1.a)) { return Pair.of(k2, wp.get(k2));