diff --git a/src/main/java/com/alibaba/testable/generator/TestableClassDevRoleGenerator.java b/src/main/java/com/alibaba/testable/generator/TestableClassDevRoleGenerator.java index cd49604..c67ab6e 100644 --- a/src/main/java/com/alibaba/testable/generator/TestableClassDevRoleGenerator.java +++ b/src/main/java/com/alibaba/testable/generator/TestableClassDevRoleGenerator.java @@ -7,6 +7,7 @@ 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.Type; @@ -51,10 +52,11 @@ public class TestableClassDevRoleGenerator { methodSpecs.add(buildMemberMethod(clazz, method)); } } - for (JCTree.JCVariableDecl field : translator.getPrivateFields()) { + for (JCTree.JCVariableDecl field : translator.getFields()) { 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) @@ -67,9 +69,21 @@ 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(Element classElement, JCTree.JCVariableDecl field) { return buildFieldAccessor(classElement, field, "TestableGet", - TypeName.get(((Type.MethodType)field.type).restype), new FieldGetterStatementGenerator()); + TypeName.get(field.vartype.type), new FieldGetterStatementGenerator()); } private MethodSpec buildFieldSetter(Element classElement, 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 77e8ee9..9cfef83 100644 --- a/src/main/java/com/alibaba/testable/processor/TestableProcessor.java +++ b/src/main/java/com/alibaba/testable/processor/TestableProcessor.java @@ -5,6 +5,7 @@ import com.alibaba.testable.generator.StaticNewClassGenerator; import com.alibaba.testable.generator.TestableClassDevRoleGenerator; import com.alibaba.testable.translator.TestableClassTestRoleTranslator; import com.alibaba.testable.util.ConstPool; +import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.tree.JCTree; import javax.annotation.processing.FilerException; @@ -40,9 +41,9 @@ public class TestableProcessor extends BaseProcessor { for (Element element : elements) { if (element.getKind().isClass()) { if (isTestClass(element.getSimpleName())) { - processTestRoleClassElement(element); + processTestRoleClassElement((Symbol.ClassSymbol)element); } else { - processDevRoleClassElement(element); + processDevRoleClassElement((Symbol.ClassSymbol)element); } } } @@ -79,7 +80,7 @@ public class TestableProcessor extends BaseProcessor { return staticNewClassFile.getName().contains(GENERATED_TEST_SOURCES); } - private void processDevRoleClassElement(Element clazz) { + private void processDevRoleClassElement(Symbol.ClassSymbol clazz) { String packageName = elementUtils.getPackageOf(clazz).getQualifiedName().toString(); String testableTypeName = getTestableClassName(clazz.getSimpleName()); String fullQualityTypeName = packageName + "." + testableTypeName; @@ -91,12 +92,16 @@ public class TestableProcessor extends BaseProcessor { } } - private void processTestRoleClassElement(Element clazz) { + private void processTestRoleClassElement(Symbol.ClassSymbol clazz) { JCTree tree = trees.getTree(clazz); - tree.accept(new TestableClassTestRoleTranslator(getOriginClassName(clazz), treeMaker)); + tree.accept(new TestableClassTestRoleTranslator(getPkgName(clazz), getOriginClassName(clazz), treeMaker)); } - private String getOriginClassName(Element clazz) { + private String getPkgName(Symbol.ClassSymbol clazz) { + return ((Symbol.PackageSymbol)clazz.owner).fullname.toString(); + } + + private String getOriginClassName(Symbol.ClassSymbol clazz) { String testClassName = clazz.getSimpleName().toString(); return testClassName.substring(0, testClassName.length() - "Test".length()); } diff --git a/src/main/java/com/alibaba/testable/translator/TestableClassDevRoleTranslator.java b/src/main/java/com/alibaba/testable/translator/TestableClassDevRoleTranslator.java index 699fca9..eff9d2a 100644 --- a/src/main/java/com/alibaba/testable/translator/TestableClassDevRoleTranslator.java +++ b/src/main/java/com/alibaba/testable/translator/TestableClassDevRoleTranslator.java @@ -28,7 +28,7 @@ public class TestableClassDevRoleTranslator extends TreeTranslator { private List methods = List.nil(); /** - * Private field to mock + * Fields to wrap */ private List fields = List.nil(); @@ -36,7 +36,7 @@ public class TestableClassDevRoleTranslator extends TreeTranslator { return methods; } - public List getPrivateFields() { + public List getFields() { return fields; } @@ -51,7 +51,7 @@ public class TestableClassDevRoleTranslator extends TreeTranslator { } /** - * record all methods + * Record all methods */ @Override public void visitMethodDef(JCMethodDecl jcMethodDecl) { @@ -60,7 +60,7 @@ public class TestableClassDevRoleTranslator extends TreeTranslator { } /** - * case: new Demo() + * Case: new Demo() */ @Override public void visitExec(JCTree.JCExpressionStatement jcExpressionStatement) { @@ -69,7 +69,7 @@ public class TestableClassDevRoleTranslator extends TreeTranslator { } /** - * case: call(new Demo()) + * Case: call(new Demo()) */ @Override public void visitApply(JCTree.JCMethodInvocation tree) { @@ -78,20 +78,20 @@ public class TestableClassDevRoleTranslator extends TreeTranslator { } /** - * record all private fields - * case: Demo d = new Demo() + * Record all private fields + * Case: Demo d = new Demo() */ @Override public void visitVarDef(JCTree.JCVariableDecl jcVariableDecl) { - if (jcVariableDecl.mods.getFlags().contains(javax.lang.model.element.Modifier.PRIVATE)) { - fields.append(jcVariableDecl); + if (isStubbornField(jcVariableDecl.mods)) { + fields = fields.append(jcVariableDecl); } jcVariableDecl.init = checkAndExchangeNewOperation(jcVariableDecl.init); super.visitVarDef(jcVariableDecl); } /** - * case: new Demo().call() + * Case: new Demo().call() */ @Override public void visitSelect(JCTree.JCFieldAccess jcFieldAccess) { @@ -99,16 +99,27 @@ public class TestableClassDevRoleTranslator extends TreeTranslator { super.visitSelect(jcFieldAccess); } + /** + * For break point + */ @Override public void visitNewClass(JCTree.JCNewClass jcNewClass) { super.visitNewClass(jcNewClass); } + /** + * For break point + */ @Override public void visitNewArray(JCTree.JCNewArray jcNewArray) { super.visitNewArray(jcNewArray); } + private boolean isStubbornField(JCTree.JCModifiers mods) { + return mods.getFlags().contains(javax.lang.model.element.Modifier.PRIVATE) || + mods.getFlags().contains(javax.lang.model.element.Modifier.FINAL); + } + private List checkAndExchangeNewOperation(List args) { if (args != null) { JCTree.JCExpression[] es = new JCTree.JCExpression[args.length()]; diff --git a/src/main/java/com/alibaba/testable/translator/TestableClassTestRoleTranslator.java b/src/main/java/com/alibaba/testable/translator/TestableClassTestRoleTranslator.java index 608013a..21d2083 100644 --- a/src/main/java/com/alibaba/testable/translator/TestableClassTestRoleTranslator.java +++ b/src/main/java/com/alibaba/testable/translator/TestableClassTestRoleTranslator.java @@ -7,6 +7,7 @@ import com.sun.tools.javac.tree.TreeTranslator; import com.sun.tools.javac.util.Name; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** @@ -19,10 +20,19 @@ public class TestableClassTestRoleTranslator extends TreeTranslator { private TreeMaker treeMaker; private String sourceClassName; private List sourceClassIns = new ArrayList<>(); + private List stubbornFields = new ArrayList<>(); - public TestableClassTestRoleTranslator(String className, TreeMaker treeMaker) { + public TestableClassTestRoleTranslator(String pkgName, String className, TreeMaker treeMaker) { this.sourceClassName = className; this.treeMaker = treeMaker; + try { + stubbornFields = Arrays.asList( + (String[])Class.forName(pkgName + "." + className + ConstPool.TESTABLE) + .getMethod(ConstPool.STUBBORN_FIELD_METHOD) + .invoke(null)); + } catch (Exception e) { + e.printStackTrace(); + } } @Override @@ -42,6 +52,37 @@ public class TestableClassTestRoleTranslator extends TreeTranslator { } } + /** + * For break point + */ + @Override + public void visitAssign(JCTree.JCAssign jcAssign) { + super.visitAssign(jcAssign); + } + + /** + * For break point + */ + @Override + public void visitSelect(JCTree.JCFieldAccess jcFieldAccess) { + super.visitSelect(jcFieldAccess); + } + + @Override + public void visitExec(JCTree.JCExpressionStatement jcExpressionStatement) { + if (jcExpressionStatement.expr.getClass().equals(JCTree.JCAssign.class) && + isAssignStubbornField((JCTree.JCAssign)jcExpressionStatement.expr)) { + //jcExpressionStatement.expr = + } + super.visitExec(jcExpressionStatement); + } + + private boolean isAssignStubbornField(JCTree.JCAssign expr) { + return expr.lhs.getClass().equals(JCTree.JCFieldAccess.class) && + sourceClassIns.contains(((JCTree.JCIdent)((JCTree.JCFieldAccess)(expr).lhs).selected).name) && + stubbornFields.contains(((JCTree.JCFieldAccess)(expr).lhs).name.toString()); + } + private JCTree.JCIdent getTestableClassIdent(JCTree.JCExpression clazz) { Name className = ((JCTree.JCIdent)clazz).name; return treeMaker.Ident(className.table.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 19c23c1..b30a531 100644 --- a/src/main/java/com/alibaba/testable/util/ConstPool.java +++ b/src/main/java/com/alibaba/testable/util/ConstPool.java @@ -12,4 +12,6 @@ public final class ConstPool { 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 STUBBORN_FIELD_METHOD = "stubbornField"; + }