- apt是javac提供的工具,他不能改变源文件,只能生成新的文件
- 自定义的注解处理器需要先注册(@AutoService(Processor.class))
- 在库中可以指明要使用的注解处理器库(annotationProcessor project(path: ':brouter_processor'))
一般我们会将注解处理器单独放在一个库中,因为他只是在编译阶段辅助生成java文件,生成的apk并不需要用到这个库,所以不会对apk的体积产生影响。
boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv);
一般来说,这个方法使用了做一些初始化工作的,但是它可以搞一些骚操作。
比如,我们通常生成 java 文件是在 javax.annotation.processing.Processor#process
中,但是有时候我们可能有这样的需求,那就是,当 module 里面没有对应的注解时,我们也想生成 java 文件,该怎么办呢?
我们看看 processor 的方法调用逻辑:
首先,它会执行 init 方法,然后会调用 javax.annotation.processing.AbstractProcessor#getSupportedAnnotationTypes
(这些方法只会被调用一次)等方法,最后再调用 process 方法。
所以,就算 module 里面没有指定的注解,注解处理器的 init 方法也会被调用。javax.annotation.processing.AbstractProcessor#getSupportedAnnotationTypes
这个方法并不影响 init 方法。
最后的解决方法,就是将生成 java 类的逻辑,放入到 init 里面。
Set getSupportedAnnotationTypes();
这里你必须指定,这个注解处理器是注册给哪个注解的,换句话说,你在这里定义你的注解处理器注册到哪些注解上,返回空会导致注解处理器拿不到任何注解修饰的元素。注意,它的返回值是一个字符串的集合,包含本处理器想要处理的注解类型的合法全称。
我们知道,注解处理器里面可以有方法,但是返回值是有限制的,看这样的一个注解:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.CLASS)
public @interface Conditional {
Class<?> condition();
}
这个注解的 conditions 方法返回了一个 class 对象。这没什么大不了的,但是我们在注解处理器中,获取该值的时候,获取不到,这是为什么呢?
final Class<?> interceptor = anno.condition(); // 代码无法往下执行
最后,发现原来是这个方法报错了,然后更奇葩的是,只能在 catch 里面取获取这个值:
try {
final Class<?> interceptor = anno.condition();
} catch (MirroredTypesException e) {
// 这里是全类名
final String className = e.getTypeMirrors().get(0).toString();
}