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开源库进行编写,提升效率