From 3e90422cb68f0dc9ae9f14717ec9eb312d35f296 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=87=91=E6=88=9F?= Date: Thu, 14 May 2020 18:33:26 +0800 Subject: [PATCH] move static new method to global class --- .../generator/StaticNewClassGenerator.java | 48 +++++++++++++++++++ .../generator/TestableClassGenerator.java | 30 ++---------- .../testable/processor/TestableProcessor.java | 32 +++++++++++-- .../com/alibaba/testable/util/ConstPool.java | 3 ++ 4 files changed, 84 insertions(+), 29 deletions(-) create mode 100644 src/main/java/com/alibaba/testable/generator/StaticNewClassGenerator.java diff --git a/src/main/java/com/alibaba/testable/generator/StaticNewClassGenerator.java b/src/main/java/com/alibaba/testable/generator/StaticNewClassGenerator.java new file mode 100644 index 0000000..c219240 --- /dev/null +++ b/src/main/java/com/alibaba/testable/generator/StaticNewClassGenerator.java @@ -0,0 +1,48 @@ +package com.alibaba.testable.generator; + +import com.alibaba.testable.util.ConstPool; +import com.squareup.javapoet.*; + +import javax.lang.model.element.Modifier; +import java.util.ArrayList; +import java.util.List; + +/** + * Generate global n.e class code + * + * @author flin + */ +public class StaticNewClassGenerator { + + public String fetch() { + return JavaFile.builder(ConstPool.SN_PKG, + TypeSpec.classBuilder(ConstPool.SN_CLS) + .addModifiers(Modifier.PUBLIC, Modifier.FINAL) + .addMethod(buildStaticNewMethod()) + .build()) + .build().toString(); + } + + private MethodSpec buildStaticNewMethod() { + TypeVariableName typeVariable = TypeVariableName.get("T"); + MethodSpec.Builder builder = MethodSpec.methodBuilder(ConstPool.SN_METHOD) + .addModifiers(Modifier.PUBLIC).addModifiers(Modifier.STATIC) + .addException(Exception.class) + .addTypeVariable(typeVariable) + .varargs(true) + .addParameter(ParameterizedTypeName.get(ClassName.get(Class.class), typeVariable), "type") + .addParameter(ArrayTypeName.of(Object.class), "args") + .returns(typeVariable); + addStaticNewMethodStatement(builder); + return builder.build(); + } + + private void addStaticNewMethodStatement(MethodSpec.Builder builder) { + builder.addStatement("$T<$T> pts = new $T<>()", List.class, Class.class, ArrayList.class) + .beginControlFlow("for (Object o : args)") + .addStatement("pts.add(o.getClass())") + .endControlFlow() + .addStatement("return type.getConstructor(pts.toArray(new Class[0])).newInstance(args)"); + } + +} diff --git a/src/main/java/com/alibaba/testable/generator/TestableClassGenerator.java b/src/main/java/com/alibaba/testable/generator/TestableClassGenerator.java index 26d246d..5647c6c 100644 --- a/src/main/java/com/alibaba/testable/generator/TestableClassGenerator.java +++ b/src/main/java/com/alibaba/testable/generator/TestableClassGenerator.java @@ -7,6 +7,7 @@ import com.squareup.javapoet.*; import com.sun.tools.javac.api.JavacTrees; import com.sun.tools.javac.code.Type; import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.TreeMaker; import javax.lang.model.element.Element; import javax.lang.model.element.Modifier; @@ -23,18 +24,19 @@ import java.util.Set; public class TestableClassGenerator { private final JavacTrees trees; + private final TreeMaker treeMaker; - public TestableClassGenerator(JavacTrees trees) { + public TestableClassGenerator(JavacTrees trees, TreeMaker treeMaker) { this.trees = trees; + this.treeMaker = treeMaker; } public String fetch(Element clazz, String packageName, String className) { JCTree tree = trees.getTree(clazz); - TestableClassTranslator translator = new TestableClassTranslator(); + TestableClassTranslator translator = new TestableClassTranslator(treeMaker); tree.accept(translator); List methodSpecs = new ArrayList<>(); - methodSpecs.add(buildStaticNewMethod(clazz)); for (JCTree.JCMethodDecl method : translator.getMethods()) { if (isNoncallableMethod(method)) { continue; @@ -57,28 +59,6 @@ public class TestableClassGenerator { return javaFile.toString(); } - private MethodSpec buildStaticNewMethod(Element clazz) { - TypeVariableName typeVariable = TypeVariableName.get("T"); - MethodSpec.Builder builder = MethodSpec.methodBuilder("New") - .addModifiers(Modifier.PUBLIC).addModifiers(Modifier.STATIC) - .addException(Exception.class) - .addTypeVariable(typeVariable) - .varargs(true) - .addParameter(ParameterizedTypeName.get(ClassName.get(Class.class), typeVariable), "type") - .addParameter(ArrayTypeName.of(Object.class), "args") - .returns(typeVariable); - addStaticNewMethodStatement(builder); - return builder.build(); - } - - private void addStaticNewMethodStatement(MethodSpec.Builder builder) { - builder.addStatement("$T<$T> pts = new $T<>()", List.class, Class.class, ArrayList.class) - .beginControlFlow("for (Object o : args)") - .addStatement("pts.add(o.getClass())") - .endControlFlow() - .addStatement("return type.getConstructor(pts.toArray(new Class[0])).newInstance(args)"); - } - private MethodSpec buildMemberMethod(Element classElement, JCTree.JCMethodDecl method) { MethodSpec.Builder builder = MethodSpec.methodBuilder(method.name.toString()) .addModifiers(toPublicFlags(method.getModifiers())) diff --git a/src/main/java/com/alibaba/testable/processor/TestableProcessor.java b/src/main/java/com/alibaba/testable/processor/TestableProcessor.java index e741ba8..f387377 100644 --- a/src/main/java/com/alibaba/testable/processor/TestableProcessor.java +++ b/src/main/java/com/alibaba/testable/processor/TestableProcessor.java @@ -1,6 +1,7 @@ package com.alibaba.testable.processor; import com.alibaba.testable.annotation.Testable; +import com.alibaba.testable.generator.StaticNewClassGenerator; import com.alibaba.testable.generator.TestableClassGenerator; import com.alibaba.testable.translator.TestableFieldTranslator; import com.alibaba.testable.util.ConstPool; @@ -13,11 +14,14 @@ import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.Name; import javax.lang.model.element.TypeElement; +import javax.tools.FileObject; import javax.tools.JavaFileObject; import java.io.IOException; import java.io.Writer; import java.util.Set; +import static javax.tools.StandardLocation.SOURCE_OUTPUT; + /** * @author flin */ @@ -25,9 +29,13 @@ import java.util.Set; @SupportedSourceVersion(SourceVersion.RELEASE_7) public class TestableProcessor extends BaseProcessor { + private static final String JAVA_POSTFIX = ".java"; + private static final String GENERATED_TEST_SOURCES = "generated-test-sources"; + @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { Set elements = roundEnv.getElementsAnnotatedWith(Testable.class); + createStaticNewClass(); for (Element element : elements) { if (element.getKind().isClass()) { processClassElement(element); @@ -38,6 +46,17 @@ public class TestableProcessor extends BaseProcessor { return true; } + private void createStaticNewClass() { + try { + FileObject staticNewClassFile = filter.getResource(SOURCE_OUTPUT, ConstPool.SN_PKG, ConstPool.SN_CLS + JAVA_POSTFIX); + if (!staticNewClassFile.getName().contains(GENERATED_TEST_SOURCES) && staticNewClassFile.getLastModified() == 0) { + writeSourceFile(ConstPool.SN_PKG + "." + ConstPool.SN_CLS, new StaticNewClassGenerator().fetch()); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + private void processFieldElement(Element field) { JCTree tree = trees.getTree(field); tree.accept(new TestableFieldTranslator(treeMaker)); @@ -48,15 +67,20 @@ public class TestableProcessor extends BaseProcessor { String testableTypeName = getTestableClassName(clazz.getSimpleName()); String fullQualityTypeName = packageName + "." + testableTypeName; try { - JavaFileObject jfo = filter.createSourceFile(fullQualityTypeName); - Writer writer = jfo.openWriter(); - writer.write(new TestableClassGenerator(trees).fetch(clazz, packageName, testableTypeName)); - writer.close(); + writeSourceFile(fullQualityTypeName, + new TestableClassGenerator(trees, treeMaker).fetch(clazz, packageName, testableTypeName)); } catch (IOException e) { e.printStackTrace(); } } + private void writeSourceFile(String fullQualityTypeName, String content) throws IOException { + JavaFileObject jfo = filter.createSourceFile(fullQualityTypeName); + Writer writer = jfo.openWriter(); + writer.write(content); + writer.close(); + } + private String getTestableClassName(Name className) { return className.toString().replace(".", "_") + 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 a3d05cb..69ec0a7 100644 --- a/src/main/java/com/alibaba/testable/util/ConstPool.java +++ b/src/main/java/com/alibaba/testable/util/ConstPool.java @@ -8,5 +8,8 @@ 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"; }