基础工程
先创建名为 AnnotationDemo 工程,如果已有工程可直接跳过:
注解类组件
工程内新建名为 annotation 的模块。
此模块存放所有注解类,示例注解类名名为 XAnnotation。
1
2
3
4
5
6
7
8
9
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface XAnnotation {
}
因为此注解可用于修饰类,所以目标类型为:ElementType.TYPE,并且注解信息在运行时保留。
注解处理器组件
另外新建模块 annotation_processor 用于存放注解处理器。存放注解处理器的模块必须和注解类模块分离,不然上层模块依赖后会出现问题。
创建之后模块布局就是这样:
然后,在模块里添加 javapoet 或 kotlinpoet 依赖,推荐使用 javapoet。还要导入上述创建的 annotation 模块,这样注解处理器就能识别我们声明的所有注解类。
1
2
3
4
5
6
7
8
9
10
apply plugin: 'java-library'
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.squareup:javapoet:1.11.1'
implementation project(":annotation")
}
sourceCompatibility = "8"
targetCompatibility = "8"
javapoet 或 kotlinpoet 的功能是通过代码编写,在编译前用预设代码拼接出新的类。根据名字就知道他们分别能生成java代码和kotlin代码。
创建注解处理器:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@SupportedAnnotationTypes({"com.phantomvk.annotation.XAnnotation"})
public class XProcessor extends AbstractProcessor {
private Filer mFiler;
private Messager mMessager;
private Elements mElementUtils;
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
mFiler = processingEnvironment.getFiler();
mMessager = processingEnvironment.getMessager();
mElementUtils = processingEnvironment.getElementUtils();
}
@Override
public Set<String> getSupportedAnnotationTypes() {
Set<String> types = new LinkedHashSet<>();
types.add(XAnnotation.class.getCanonicalName());
return types;
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.RELEASE_8;
}
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
// 返回false编译不会通过,必须把输入的代码输出到目标目录
return false;
}
}
继续完善 process() 的逻辑:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(XAnnotation.class);
for (Element element : elements) {
PackageElement packageElement = mElementUtils.getPackageOf(element);
String packageName = packageElement.getQualifiedName().toString();
MethodSpec methodSpec = MethodSpec.methodBuilder("showLog") // 方法名
.addModifiers(Modifier.PUBLIC, Modifier.STATIC) // 声明为公开的静态方法
.returns(void.class) // 返回值为空
.addStatement("$T.out.println($S)", System.class, "Hello JavaPoet.") // 方法体
.build();
TypeSpec typeSpec = TypeSpec.classBuilder("XGeneratedClass") // 类名
.addModifiers(Modifier.PUBLIC) // 类可见性为public
.addMethod(methodSpec) // 把上述方法添加到类,可继续添加
.build();
// 用构建完成的类生成Java文件
JavaFile javaFile = JavaFile.builder(packageName, typeSpec).build();
try {
// 结果写入磁盘
javaFile.writeTo(mFiler);
} catch (IOException e) {
e.printStackTrace();
}
}
return true;
}
注册上述注解处理器:
注册声明文件必须按照上述目录存放而且有文件名:
1
javax.annotation.processing.Processor
文件内容为注解处理器的全路径名:
只有正确注册的注解处理器,编译器才能在编译过程处理注解并执行注解逻辑。
导入
最后在App工程导入注解声明库和注解处理器库:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
apply plugin: 'kotlin-kapt'
// JavaPoet required Java8
android {
compileOptions {
sourceCompatibility 1.8
targetCompatibility 1.8
}
}
dependencies {
// ....
implementation project(":annotation")
kapt project(":annotation_processor") // annotationProcessor for Java
}
导入之后就可以用声明好的注解类修饰 MainActivity:
1
2
3
4
5
6
7
8
@XAnnotation
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
点击构建就会按照注解类能获取的信息生成新的类 XGeneratedClass:
同时项目也能引用生成类:
1
2
3
4
5
6
7
8
@XAnnotation
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
XGeneratedClass.showLog() // 直接引用
}
}
执行结果
运行之后控制台就能打印:
1
com.phantomvk.annotationdemo I/System.out: Hello JavaPoet.
上述文章完成声明和开发注解处理器最基本的方式,后续将在此基础上继续增强注解处理器的能力。
完整工程源码:phantomVK/AnnotationDemo