編譯時註解(一)AbstractProcessor實戰
阿新 • • 發佈:2018-12-19
Java中的註解(Annotation)是一個很神奇的東西,特別現在有很多Android庫都是使用註解的方式來實現的。 我們並不討論那些在執行時(Runtime)通過反射機制執行處理的註解,而是討論在編譯時(Compile time)處理的註解。下面便入手學習下Java註解處理器。
簡單實踐: 1.建立註解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.CLASS)
public @interface MethodProcessor {
String name() default "Method";
}
接下來就可以使用了
@MethodProcessor(name = "Method")
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
2.註解處理器 上面只是講如何運用,其實內部是如何生成的暫時還不知道,往下看。
//@AutoService(Processor.class) 這個有木有?這是一個註解處理器,是Google開發的, //用來生成META-INF/services/javax.annotation.processing.Processor檔案的。 //引入方式 compile 'com.google.auto.service:auto-service:1.0-rc2' @AutoService(Processor.class) public class MyProcessor extends AbstractProcessor { private Types mTypeUtils; private Elements mElementUtils; private Filer mFiler; private Messager mMessager; @Override public Set<String> getSupportedAnnotationTypes() { Set<String> annotations = new LinkedHashSet<>(); //把我們自己定義的註解新增進去 annotations.add(MethodProcessor.class.getCanonicalName()); return annotations; } @Override public SourceVersion getSupportedSourceVersion() { return SourceVersion.latestSupported(); } @Override public synchronized void init(ProcessingEnvironment processingEnv) { super.init(processingEnv); mTypeUtils = processingEnv.getTypeUtils(); mElementUtils = processingEnv.getElementUtils(); mFiler = processingEnv.getFiler(); mMessager = processingEnv.getMessager(); } @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { // // 遍歷所有被註解了的元素 for (Element annotatedElement : roundEnv.getElementsAnnotatedWith(MethodProcessor.class)) { if (annotatedElement.getKind() != ElementKind.CLASS) { error(annotatedElement, "Only classes can be annotated with @%s", MethodProcessor.class.getSimpleName()); return true; } // //解析,並生成程式碼 analysisAnnotated(annotatedElement); } return false; } private void error(Element e, String msg, Object... args) { mMessager.printMessage(Diagnostic.Kind.ERROR, String.format(msg, args), e); } private static final String SUFFIX = "Test"; private static final String packageName = "com.company.processtest"; private static final String retStr = ""; private void analysisAnnotated(Element classElement) { MethodProcessor annotation = classElement.getAnnotation(MethodProcessor.class); String name = annotation.name(); String newClassName = name + SUFFIX; StringBuilder builder = new StringBuilder() .append("package " + packageName + ";\n\n") .append("public class ") .append(newClassName) .append(" {\n\n") // open class .append("\tpublic String getMessage() {\n") // open method .append("\t\treturn \""); // this is appending to the return statement builder.append(retStr).append(" !\\n"); builder.append("\";\n") // end return .append("\t}\n") // close method .append("}\n"); // close class try { // write the file JavaFileObject source = mFiler.createSourceFile(packageName + "." + newClassName); Writer writer = source.openWriter(); writer.write(builder.toString()); writer.flush(); writer.close(); } catch (IOException e) { } } }
最後build一下工程,生成最終的java檔案 檔案位置ProcessTest\app\build\generated\source\apt\debug\com\company\processtest\MethodTest.java
package com.company.processtest;
public class MethodTest {
public String getMessage() {
return "this is just a test !\n";
}
}
這樣,就可以使用這個類了
@MethodProcessor(name = "Method") public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); MethodTest test = new MethodTest(); test.getMessage(); } }
注意:註解類和AbstractProcessor必須要新建一個java庫。
AbstractProcessor中生成java類,可以使用JavaPoet開源庫進行編寫,提升效率