add private field access generators

This commit is contained in:
金戟 2020-05-16 21:13:41 +08:00
parent 12ddb9398c
commit cbb3a62fff
9 changed files with 141 additions and 12 deletions

View File

@ -1,6 +1,10 @@
package com.alibaba.testable.generator; package com.alibaba.testable.generator;
import com.alibaba.testable.generator.model.Statement; 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.translator.TestableClassDevRoleTranslator;
import com.alibaba.testable.util.ConstPool; import com.alibaba.testable.util.ConstPool;
import com.squareup.javapoet.*; import com.squareup.javapoet.*;
@ -47,6 +51,10 @@ public class TestableClassDevRoleGenerator {
methodSpecs.add(buildMemberMethod(clazz, method)); methodSpecs.add(buildMemberMethod(clazz, method));
} }
} }
for (JCTree.JCVariableDecl field : translator.getPrivateFields()) {
methodSpecs.add(buildFieldGetter(clazz, field));
methodSpecs.add(buildFieldSetter(clazz, field));
}
TypeSpec.Builder builder = TypeSpec.classBuilder(className) TypeSpec.Builder builder = TypeSpec.classBuilder(className)
.addModifiers(Modifier.PUBLIC, Modifier.FINAL) .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
@ -59,6 +67,29 @@ public class TestableClassDevRoleGenerator {
return javaFile.toString(); return javaFile.toString();
} }
private MethodSpec buildFieldGetter(Element classElement, JCTree.JCVariableDecl field) {
return buildFieldAccessor(classElement, field, "TestableGet",
TypeName.get(((Type.MethodType)field.type).restype), 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)
.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();
}
private MethodSpec buildMemberMethod(Element classElement, JCTree.JCMethodDecl method) { private MethodSpec buildMemberMethod(Element classElement, JCTree.JCMethodDecl method) {
MethodSpec.Builder builder = MethodSpec.methodBuilder(method.name.toString()) MethodSpec.Builder builder = MethodSpec.methodBuilder(method.name.toString())
.addModifiers(toPublicFlags(method.getModifiers())) .addModifiers(toPublicFlags(method.getModifiers()))
@ -79,8 +110,7 @@ public class TestableClassDevRoleGenerator {
} }
private MethodSpec buildConstructorMethod(Element classElement, JCTree.JCMethodDecl method) { private MethodSpec buildConstructorMethod(Element classElement, JCTree.JCMethodDecl method) {
MethodSpec.Builder builder = MethodSpec.constructorBuilder() MethodSpec.Builder builder = MethodSpec.constructorBuilder().addModifiers(Modifier.PUBLIC);
.addModifiers(Modifier.PUBLIC);
for (JCTree.JCVariableDecl p : method.getParameters()) { for (JCTree.JCVariableDecl p : method.getParameters()) {
builder.addParameter(getParameterSpec(p)); builder.addParameter(getParameterSpec(p));
} }

View File

@ -1,4 +1,4 @@
package com.alibaba.testable.generator; package com.alibaba.testable.generator.statement;
import com.alibaba.testable.generator.model.Statement; import com.alibaba.testable.generator.model.Statement;
import com.alibaba.testable.util.ConstPool; import com.alibaba.testable.util.ConstPool;

View File

@ -0,0 +1,25 @@
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[] {})};
}
}

View File

@ -0,0 +1,25 @@
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[]{};
}
}

View File

@ -0,0 +1,14 @@
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);
}

View File

@ -91,9 +91,14 @@ public class TestableProcessor extends BaseProcessor {
} }
} }
private void processTestRoleClassElement(Element field) { private void processTestRoleClassElement(Element clazz) {
JCTree tree = trees.getTree(field); JCTree tree = trees.getTree(clazz);
tree.accept(new TestableClassTestRoleTranslator(treeMaker)); tree.accept(new TestableClassTestRoleTranslator(getOriginClassName(clazz), treeMaker));
}
private String getOriginClassName(Element clazz) {
String testClassName = clazz.getSimpleName().toString();
return testClassName.substring(0, testClassName.length() - "Test".length());
} }
private void writeSourceFile(String fullQualityTypeName, String content) throws IOException { private void writeSourceFile(String fullQualityTypeName, String content) throws IOException {

View File

@ -27,10 +27,19 @@ public class TestableClassDevRoleTranslator extends TreeTranslator {
*/ */
private List<JCMethodDecl> methods = List.nil(); private List<JCMethodDecl> methods = List.nil();
/**
* Private field to mock
*/
private List<JCTree.JCVariableDecl> fields = List.nil();
public List<JCMethodDecl> getMethods() { public List<JCMethodDecl> getMethods() {
return methods; return methods;
} }
public List<JCTree.JCVariableDecl> getPrivateFields() {
return fields;
}
public TestableClassDevRoleTranslator(TreeMaker treeMaker) { public TestableClassDevRoleTranslator(TreeMaker treeMaker) {
this.treeMaker = treeMaker; this.treeMaker = treeMaker;
} }
@ -69,10 +78,14 @@ public class TestableClassDevRoleTranslator extends TreeTranslator {
} }
/** /**
* record all private fields
* case: Demo d = new Demo() * case: Demo d = new Demo()
*/ */
@Override @Override
public void visitVarDef(JCTree.JCVariableDecl jcVariableDecl) { public void visitVarDef(JCTree.JCVariableDecl jcVariableDecl) {
if (jcVariableDecl.mods.getFlags().contains(javax.lang.model.element.Modifier.PRIVATE)) {
fields.append(jcVariableDecl);
}
jcVariableDecl.init = checkAndExchangeNewOperation(jcVariableDecl.init); jcVariableDecl.init = checkAndExchangeNewOperation(jcVariableDecl.init);
super.visitVarDef(jcVariableDecl); super.visitVarDef(jcVariableDecl);
} }
@ -91,6 +104,11 @@ public class TestableClassDevRoleTranslator extends TreeTranslator {
super.visitNewClass(jcNewClass); super.visitNewClass(jcNewClass);
} }
@Override
public void visitNewArray(JCTree.JCNewArray jcNewArray) {
super.visitNewArray(jcNewArray);
}
private List<JCTree.JCExpression> checkAndExchangeNewOperation(List<JCTree.JCExpression> args) { private List<JCTree.JCExpression> checkAndExchangeNewOperation(List<JCTree.JCExpression> args) {
if (args != null) { if (args != null) {
JCTree.JCExpression[] es = new JCTree.JCExpression[args.length()]; JCTree.JCExpression[] es = new JCTree.JCExpression[args.length()];

View File

@ -6,6 +6,9 @@ import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.tree.TreeTranslator; import com.sun.tools.javac.tree.TreeTranslator;
import com.sun.tools.javac.util.Name; import com.sun.tools.javac.util.Name;
import java.util.ArrayList;
import java.util.List;
/** /**
* Travel AST * Travel AST
* *
@ -14,19 +17,29 @@ import com.sun.tools.javac.util.Name;
public class TestableClassTestRoleTranslator extends TreeTranslator { public class TestableClassTestRoleTranslator extends TreeTranslator {
private TreeMaker treeMaker; private TreeMaker treeMaker;
private String sourceClassName;
private List<Name> sourceClassIns = new ArrayList<>();
public TestableClassTestRoleTranslator(TreeMaker treeMaker) {this.treeMaker = treeMaker;} public TestableClassTestRoleTranslator(String className, TreeMaker treeMaker) {
this.sourceClassName = className;
this.treeMaker = treeMaker;
}
@Override @Override
public void visitVarDef(JCTree.JCVariableDecl decl) { public void visitVarDef(JCTree.JCVariableDecl jcVariableDecl) {
super.visitVarDef(decl); super.visitVarDef(jcVariableDecl);
decl.vartype = getTestableClassIdent(decl.vartype); if (((JCTree.JCIdent)jcVariableDecl.vartype).name.toString().equals(sourceClassName)) {
jcVariableDecl.vartype = getTestableClassIdent(jcVariableDecl.vartype);
sourceClassIns.add(jcVariableDecl.name);
}
} }
@Override @Override
public void visitNewClass(JCTree.JCNewClass jcNewClass) { public void visitNewClass(JCTree.JCNewClass jcNewClass) {
super.visitNewClass(jcNewClass); super.visitNewClass(jcNewClass);
jcNewClass.clazz = getTestableClassIdent(jcNewClass.clazz); if (((JCTree.JCIdent)jcNewClass.clazz).name.toString().equals(sourceClassName)) {
jcNewClass.clazz = getTestableClassIdent(jcNewClass.clazz);
}
} }
private JCTree.JCIdent getTestableClassIdent(JCTree.JCExpression clazz) { private JCTree.JCIdent getTestableClassIdent(JCTree.JCExpression clazz) {

View File

@ -1,2 +1 @@
com.alibaba.testable.processor.TestableProcessor com.alibaba.testable.processor.TestableProcessor
com.alibaba.testable.processor.TestableInjectProcessor