From ce296710d9942bc8af6f3902e24f323201431b2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=87=91=E6=88=9F?= Date: Sun, 17 May 2020 01:22:51 +0800 Subject: [PATCH] generate correct setter and getter --- .../TestableClassDevRoleGenerator.java | 63 +++++++++++-------- .../FieldGetterStatementGenerator.java | 25 -------- .../FieldSetterStatementGenerator.java | 25 -------- .../statement/FieldStatementGenerator.java | 14 ----- .../testable/processor/TestableProcessor.java | 4 +- .../TestableClassDevRoleTranslator.java | 19 +++--- .../TestableClassTestRoleTranslator.java | 20 +++++- .../com/alibaba/testable/util/ConstPool.java | 3 + 8 files changed, 69 insertions(+), 104 deletions(-) delete mode 100644 src/main/java/com/alibaba/testable/generator/statement/FieldGetterStatementGenerator.java delete mode 100644 src/main/java/com/alibaba/testable/generator/statement/FieldSetterStatementGenerator.java delete mode 100644 src/main/java/com/alibaba/testable/generator/statement/FieldStatementGenerator.java diff --git a/src/main/java/com/alibaba/testable/generator/TestableClassDevRoleGenerator.java b/src/main/java/com/alibaba/testable/generator/TestableClassDevRoleGenerator.java index c67ab6e..30133ec 100644 --- a/src/main/java/com/alibaba/testable/generator/TestableClassDevRoleGenerator.java +++ b/src/main/java/com/alibaba/testable/generator/TestableClassDevRoleGenerator.java @@ -2,20 +2,20 @@ package com.alibaba.testable.generator; import com.alibaba.testable.generator.model.Statement; import com.alibaba.testable.generator.statement.CallSuperMethodStatementGenerator; -import com.alibaba.testable.generator.statement.FieldGetterStatementGenerator; -import com.alibaba.testable.generator.statement.FieldSetterStatementGenerator; -import com.alibaba.testable.generator.statement.FieldStatementGenerator; 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.api.JavacTrees; +import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.code.Type; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.TreeMaker; +import com.sun.tools.javac.util.Names; import javax.lang.model.element.Element; import javax.lang.model.element.Modifier; +import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -30,15 +30,17 @@ public class TestableClassDevRoleGenerator { private final JavacTrees trees; private final TreeMaker treeMaker; + private final Names names; - public TestableClassDevRoleGenerator(JavacTrees trees, TreeMaker treeMaker) { + public TestableClassDevRoleGenerator(JavacTrees trees, TreeMaker treeMaker, Names names) { this.trees = trees; this.treeMaker = treeMaker; + this.names = names; } - public String fetch(Element clazz, String packageName, String className) { + public String fetch(Symbol.ClassSymbol clazz, String packageName, String className) { JCTree tree = trees.getTree(clazz); - TestableClassDevRoleTranslator translator = new TestableClassDevRoleTranslator(treeMaker); + TestableClassDevRoleTranslator translator = new TestableClassDevRoleTranslator(treeMaker, names); tree.accept(translator); List methodSpecs = new ArrayList<>(); @@ -81,27 +83,36 @@ public class TestableClassDevRoleGenerator { .build(); } - private MethodSpec buildFieldGetter(Element classElement, JCTree.JCVariableDecl field) { - return buildFieldAccessor(classElement, field, "TestableGet", - TypeName.get(field.vartype.type), new FieldGetterStatementGenerator()); - } - - private MethodSpec buildFieldSetter(Element classElement, JCTree.JCVariableDecl field) { - return buildFieldAccessor(classElement, field, "TestableSet", - TypeName.VOID, new FieldSetterStatementGenerator()); - } - - private MethodSpec buildFieldAccessor(Element classElement, JCTree.JCVariableDecl field, String prefix, - TypeName returnType, FieldStatementGenerator generator) { - MethodSpec.Builder builder = MethodSpec.methodBuilder(field.name.toString() + prefix) + private MethodSpec buildFieldGetter(Symbol.ClassSymbol classElement, JCTree.JCVariableDecl field) { + String fieldName = field.name.toString(); + return MethodSpec.methodBuilder(fieldName + ConstPool.TESTABLE_GET_METHOD_PREFIX) .addModifiers(Modifier.PUBLIC) - .returns(returnType); - String className = classElement.getSimpleName().toString(); - Statement[] statements = generator.fetch(className, field); - for (Statement s : statements) { - builder.addStatement(s.getLine(), s.getParams()); - } - return builder.build(); + .returns(TypeName.get(field.vartype.type)) + .beginControlFlow("try") + .addStatement("$T field = $T.class.getDeclaredField(\"$N\")", Field.class, classElement.type, fieldName) + .addStatement("field.setAccessible(true)") + .addStatement("return ($T)field.get(this)", field.vartype.type) + .nextControlFlow("catch ($T e)", Exception.class) + .addStatement("e.printStackTrace()") + .addStatement("return null") + .endControlFlow() + .build(); + } + + private MethodSpec buildFieldSetter(Symbol.ClassSymbol classElement, JCTree.JCVariableDecl field) { + String fieldName = field.name.toString(); + return MethodSpec.methodBuilder(fieldName + ConstPool.TESTABLE_SET_METHOD_PREFIX) + .addModifiers(Modifier.PUBLIC) + .addParameter(getParameterSpec(field)) + .returns(TypeName.VOID) + .beginControlFlow("try") + .addStatement("$T field = $T.class.getDeclaredField(\"$N\")", Field.class, classElement.type, fieldName) + .addStatement("field.setAccessible(true)") + .addStatement("field.set(this, $N)", fieldName) + .nextControlFlow("catch ($T e)", Exception.class) + .addStatement("e.printStackTrace()") + .endControlFlow() + .build(); } private MethodSpec buildMemberMethod(Element classElement, JCTree.JCMethodDecl method) { diff --git a/src/main/java/com/alibaba/testable/generator/statement/FieldGetterStatementGenerator.java b/src/main/java/com/alibaba/testable/generator/statement/FieldGetterStatementGenerator.java deleted file mode 100644 index 7edf23a..0000000 --- a/src/main/java/com/alibaba/testable/generator/statement/FieldGetterStatementGenerator.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.alibaba.testable.generator.statement; - -import com.alibaba.testable.generator.model.Statement; -import com.alibaba.testable.util.ConstPool; -import com.alibaba.testable.util.StringUtil; -import com.sun.tools.javac.tree.JCTree; - -import javax.lang.model.element.Modifier; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.List; - -/** - * Generate field getter method statement - * - * @author flin - */ -public class FieldGetterStatementGenerator implements FieldStatementGenerator { - - @Override - public Statement[] fetch(String className, JCTree.JCVariableDecl field) { - return new Statement[] {new Statement("return null", new Object[] {})}; - } - -} diff --git a/src/main/java/com/alibaba/testable/generator/statement/FieldSetterStatementGenerator.java b/src/main/java/com/alibaba/testable/generator/statement/FieldSetterStatementGenerator.java deleted file mode 100644 index c70116b..0000000 --- a/src/main/java/com/alibaba/testable/generator/statement/FieldSetterStatementGenerator.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.alibaba.testable.generator.statement; - -import com.alibaba.testable.generator.model.Statement; -import com.alibaba.testable.util.ConstPool; -import com.alibaba.testable.util.StringUtil; -import com.sun.tools.javac.tree.JCTree; - -import javax.lang.model.element.Modifier; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.List; - -/** - * Generate field setter method statement - * - * @author flin - */ -public class FieldSetterStatementGenerator implements FieldStatementGenerator { - - @Override - public Statement[] fetch(String className, JCTree.JCVariableDecl field) { - return new Statement[]{}; - } - -} diff --git a/src/main/java/com/alibaba/testable/generator/statement/FieldStatementGenerator.java b/src/main/java/com/alibaba/testable/generator/statement/FieldStatementGenerator.java deleted file mode 100644 index 5b4f443..0000000 --- a/src/main/java/com/alibaba/testable/generator/statement/FieldStatementGenerator.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.alibaba.testable.generator.statement; - -import com.alibaba.testable.generator.model.Statement; -import com.sun.tools.javac.tree.JCTree; - -/** - * @author flin - */ -public interface FieldStatementGenerator { - /** - * Generate field access code statement - */ - Statement[] fetch(String className, JCTree.JCVariableDecl field); -} diff --git a/src/main/java/com/alibaba/testable/processor/TestableProcessor.java b/src/main/java/com/alibaba/testable/processor/TestableProcessor.java index 9cfef83..0fd2f4e 100644 --- a/src/main/java/com/alibaba/testable/processor/TestableProcessor.java +++ b/src/main/java/com/alibaba/testable/processor/TestableProcessor.java @@ -86,7 +86,7 @@ public class TestableProcessor extends BaseProcessor { String fullQualityTypeName = packageName + "." + testableTypeName; try { writeSourceFile(fullQualityTypeName, - new TestableClassDevRoleGenerator(trees, treeMaker).fetch(clazz, packageName, testableTypeName)); + new TestableClassDevRoleGenerator(trees, treeMaker, names).fetch(clazz, packageName, testableTypeName)); } catch (IOException e) { e.printStackTrace(); } @@ -94,7 +94,7 @@ public class TestableProcessor extends BaseProcessor { private void processTestRoleClassElement(Symbol.ClassSymbol clazz) { JCTree tree = trees.getTree(clazz); - tree.accept(new TestableClassTestRoleTranslator(getPkgName(clazz), getOriginClassName(clazz), treeMaker)); + tree.accept(new TestableClassTestRoleTranslator(getPkgName(clazz), getOriginClassName(clazz), treeMaker, names)); } private String getPkgName(Symbol.ClassSymbol clazz) { diff --git a/src/main/java/com/alibaba/testable/translator/TestableClassDevRoleTranslator.java b/src/main/java/com/alibaba/testable/translator/TestableClassDevRoleTranslator.java index eff9d2a..8c476b0 100644 --- a/src/main/java/com/alibaba/testable/translator/TestableClassDevRoleTranslator.java +++ b/src/main/java/com/alibaba/testable/translator/TestableClassDevRoleTranslator.java @@ -10,6 +10,7 @@ import com.sun.tools.javac.tree.TreeTranslator; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Name; +import com.sun.tools.javac.util.Names; import java.lang.reflect.Modifier; @@ -21,6 +22,7 @@ import java.lang.reflect.Modifier; public class TestableClassDevRoleTranslator extends TreeTranslator { private final TreeMaker treeMaker; + private final Names names; /** * Methods to inject @@ -40,8 +42,9 @@ public class TestableClassDevRoleTranslator extends TreeTranslator { return fields; } - public TestableClassDevRoleTranslator(TreeMaker treeMaker) { + public TestableClassDevRoleTranslator(TreeMaker treeMaker, Names names) { this.treeMaker = treeMaker; + this.names = names; } @Override @@ -135,9 +138,8 @@ public class TestableClassDevRoleTranslator extends TreeTranslator { if (isNewOperation(expr)) { JCTree.JCNewClass newClassExpr = (JCTree.JCNewClass)expr; Name className = ((JCTree.JCIdent)newClassExpr.clazz).name; - Name.Table nameTable = className.table; try { - return getStaticNewCall(newClassExpr, className, nameTable); + return getStaticNewCall(newClassExpr, className); } catch (Exception e) { e.printStackTrace(); } @@ -149,14 +151,13 @@ public class TestableClassDevRoleTranslator extends TreeTranslator { return expr != null && expr.getClass().equals(JCTree.JCNewClass.class); } - private TestableMethodInvocation getStaticNewCall(JCTree.JCNewClass newClassExpr, Name className, - Name.Table nameTable) { - TestableFieldAccess snClass = new TestableFieldAccess(treeMaker.Ident(nameTable.fromString(ConstPool.SN_PKG)), - nameTable.fromString(ConstPool.SN_CLS), null); + private TestableMethodInvocation getStaticNewCall(JCTree.JCNewClass newClassExpr, Name className) { + TestableFieldAccess snClass = new TestableFieldAccess(treeMaker.Ident(names.fromString(ConstPool.SN_PKG)), + names.fromString(ConstPool.SN_CLS), null); TestableFieldAccess snMethod = new TestableFieldAccess(snClass, - nameTable.fromString(ConstPool.SN_METHOD), null); + names.fromString(ConstPool.SN_METHOD), null); JCTree.JCExpression classType = new TestableFieldAccess(treeMaker.Ident(className), - nameTable.fromString("class"), null); + names.fromString("class"), null); ListBuffer args = ListBuffer.of(classType); args.addAll(newClassExpr.args); return new TestableMethodInvocation(null, 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 21d2083..d9fdc1a 100644 --- a/src/main/java/com/alibaba/testable/translator/TestableClassTestRoleTranslator.java +++ b/src/main/java/com/alibaba/testable/translator/TestableClassTestRoleTranslator.java @@ -1,10 +1,13 @@ package com.alibaba.testable.translator; +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.TreeMaker; import com.sun.tools.javac.tree.TreeTranslator; import com.sun.tools.javac.util.Name; +import com.sun.tools.javac.util.Names; import java.util.ArrayList; import java.util.Arrays; @@ -18,13 +21,15 @@ import java.util.List; public class TestableClassTestRoleTranslator extends TreeTranslator { private TreeMaker treeMaker; + private Names names; private String sourceClassName; private List sourceClassIns = new ArrayList<>(); private List stubbornFields = new ArrayList<>(); - public TestableClassTestRoleTranslator(String pkgName, String className, TreeMaker treeMaker) { + public TestableClassTestRoleTranslator(String pkgName, String className, TreeMaker treeMaker, Names names) { this.sourceClassName = className; this.treeMaker = treeMaker; + this.names = names; try { stubbornFields = Arrays.asList( (String[])Class.forName(pkgName + "." + className + ConstPool.TESTABLE) @@ -72,11 +77,20 @@ public class TestableClassTestRoleTranslator extends TreeTranslator { public void visitExec(JCTree.JCExpressionStatement jcExpressionStatement) { if (jcExpressionStatement.expr.getClass().equals(JCTree.JCAssign.class) && isAssignStubbornField((JCTree.JCAssign)jcExpressionStatement.expr)) { - //jcExpressionStatement.expr = + JCTree.JCAssign assign = (JCTree.JCAssign)jcExpressionStatement.expr; + TestableFieldAccess stubbornSetter = new TestableFieldAccess(((JCTree.JCFieldAccess)assign.lhs).selected, + getStubbornSetterMethodName(assign), null); + jcExpressionStatement.expr = new TestableMethodInvocation(null, stubbornSetter, + com.sun.tools.javac.util.List.of(assign.rhs)); } super.visitExec(jcExpressionStatement); } + private Name getStubbornSetterMethodName(JCTree.JCAssign assign) { + String name = ((JCTree.JCFieldAccess)assign.lhs).name.toString() + ConstPool.TESTABLE_SET_METHOD_PREFIX; + return names.fromString(name); + } + private boolean isAssignStubbornField(JCTree.JCAssign expr) { return expr.lhs.getClass().equals(JCTree.JCFieldAccess.class) && sourceClassIns.contains(((JCTree.JCIdent)((JCTree.JCFieldAccess)(expr).lhs).selected).name) && @@ -85,7 +99,7 @@ public class TestableClassTestRoleTranslator extends TreeTranslator { private JCTree.JCIdent getTestableClassIdent(JCTree.JCExpression clazz) { Name className = ((JCTree.JCIdent)clazz).name; - return treeMaker.Ident(className.table.fromString(className + ConstPool.TESTABLE)); + return treeMaker.Ident(names.fromString(className + ConstPool.TESTABLE)); } } diff --git a/src/main/java/com/alibaba/testable/util/ConstPool.java b/src/main/java/com/alibaba/testable/util/ConstPool.java index b30a531..ea53bb2 100644 --- a/src/main/java/com/alibaba/testable/util/ConstPool.java +++ b/src/main/java/com/alibaba/testable/util/ConstPool.java @@ -13,5 +13,8 @@ public final class ConstPool { public static final String SN_METHOD = "w"; public static final String SN_PKG_CLS = "n.e"; public static final String STUBBORN_FIELD_METHOD = "stubbornField"; + public static final String TESTABLE_GET_METHOD_PREFIX = "TestableGet"; + public static final String TESTABLE_SET_METHOD_PREFIX = "TestableSet"; + }