JavaPoet 和 Java 注解在 Android 中的应用

JavaPoet 结合 Java 注解在很多知名的开源库中都应用,例如 Butterknife 和 ARouter.
JavaPoet 是用来生成 .java 文件的,它的使用比较简单,按照官方的示例代码套用就可以了。
Java 的注解,有时间会整理,这里先略过。

我做了一个 Dome 说明它们的应用。
先看一下项目的结构。

整个项目包含三个部分:

  • app : 主项目,使用我们的注解
  • annotationlib: 注解
  • javapoetlib: 使用 javaPoet 生成 .java 代码

下面我们一个个来看

1. 注解

我们先生成一个 java library 生成注解, 这里不能选 android library, 命名为 annotationlib.

它的 build.gradle 文件我们不用修改, 我们看到它是 java-library

1
2
3
4
5
6
7
8
apply plugin: 'java-library'

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
}

sourceCompatibility = "1.7"
targetCompatibility = "1.7"

创建一个名为 MyAnnotation 的接口文件, 它的内容也是非常简单的

1
2
3
4
5
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)
public @interface MyAnnotation {
int action() default 0;
}

2. JavaPoet 生成 .java 文件

同样创建一个 java library, 命名为 javapoetlib, 但是它的 build.gradle 文件,我们要修改

1
2
3
4
5
6
7
8
9
10
11
apply plugin: 'java-library'

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
compile project(':annotationlib')
compile 'com.google.auto.service:auto-service:1.0-rc2'
compile 'com.squareup:javapoet:1.9.0'
}

sourceCompatibility = "1.7"
targetCompatibility = "1.7"

我们添加对刚刚创建的 annotationlib 依赖,同时添加 auto-service 和 javapoet.

我们创建一个 MyProcessor 的文件

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

@AutoService(Processor.class) // 需要添加
public class MyProcessor extends AbstractProcessor {

private Filer mFiler;
private Elements mElementUtils;
private Messager mMessager;


private static final String PACK_NAME = "com.yxhuang.temp";

@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);

mFiler = processingEnv.getFiler();
mElementUtils = processingEnv.getElementUtils();
mMessager = processingEnv.getMessager();

}

@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported(); // 版本
}

@Override
public Set<String> getSupportedAnnotationTypes() {
return Collections.singleton(MyAnnotation.class.getCanonicalName()); // 注解的类
}

@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
System.out.print("MyProcessor process");

MethodSpec main = MethodSpec.methodBuilder("main")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC) // 添加标识符 public static
.returns(void.class) // 返回类型
.addParameter(String[].class, "args") // 方法的参数
.addStatement("$T.out.println($S)", System.class, "Hello World!") // 方法里面的语句声明
.build();

// 构建 HelloWorld 类
TypeSpec hellWorld = TypeSpec.classBuilder("HelloWorld")
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.addMethod(main)
.build();

// 生成 java 文件
JavaFile javaFile = JavaFile.builder(PACK_NAME, hellWorld).build();
try {
javaFile.writeTo(mFiler);
} catch (Exception e){
e.printStackTrace();

}

return true;
}
}

相关的信息,可以看上面代码的注释

  • 主要是添加 auto 的注解
1
@AutoService(Processor.class)
  • 版本号
1
2
3
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
  • 注解的类型
1
2
3
 public Set<String> getSupportedAnnotationTypes() {
return Collections.singleton(MyAnnotation.class.getCanonicalName()); // 注解的类
}

在 process 方法中使用 JavaPoet 中的方法,生成一个输出 Hello world 的代码,这是一个官方的实例代码,关于 JavaPoet 的使用,可以去 JavaPoet github 主页 去查询。

3. 项目中对注解的使用

在项目中对上面两个 java library 引用

1
2
3
4
5
6
7
8
9
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])

annotationProcessor project(':javapoetlib')
implementation project(':annotationlib')

...

}

在 activity 中使用 annoation 注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}

@MyAnnotation(action = 2)
public void test(){

}

}

现在所有的准备工作都做好,我们选择 Make Project 即可,然后我们在 app/build/generated/source/apt/debug 目录下看到生成的 hello world 文件了

yxhuang wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客