JavaPoet是square推出的开源java代码生成框架,提供Java Api生成.java源文件。这个框架功能非常有用,我们可以很方便的使用它根据注解、数据库模式、协议格式等来对应生成代码。通过这种自动化生成代码的方式,可以让我们用更加简洁优雅的方式要替代繁琐冗杂的重复工作。
关于JavaPoet 的API使用,官方Github主页已经有很详细的使用说明和示例了,具体可前往查看。此处不赘述,详见 项目主页、源码及使用说明
使用场景
1.根据编译时注解生成代码(例如butterknife)
示例:简单演示利用编译时注解+JavaPoet来实现编译期间动态生成代码:
简单演示利用编译时注解+JavaPoet来实现编译期间动态生成代码:
工程目录结构:
- app
- annotations (注解相关)
- annotation_compiler (处理器生成代码相关)
(1)导入依赖
build.gradle (Module:app)
dependencies {
annotationProcessor 'com.neenbedankt.gradle.plugins:android-apt:1.8'
implementation project(':annotations')
annotationProcessor project(':annotation_compiler')
}
build.gradle (Module:annotation_compiler)
dependencies {
...
implementation 'com.squareup:javapoet:1.11.1'
implementation project(':annotations')
annotationProcessor 'com.google.auto.service:auto-service:1.0-rc4'
compileOnly('com.google.auto.service:auto-service:1.0-rc4')
}
(2)定义注解(Module:annotations )
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
public @interface HelloAnnotation {
}
(3)定义Processor
@AutoService(Processor.class)
public class HelloProcessor extends AbstractProcessor {
private Filer mFiler;
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
mFiler = processingEnvironment.getFiler();
}
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
for (TypeElement element : set) {
if (element.getQualifiedName().toString().equals(HelloAnnotation.class.getCanonicalName())) {
MethodSpec spec = MethodSpec.methodBuilder("setName")
.addModifiers(Modifier.PUBLIC,Modifier.STATIC)
.returns(void.class)
.addParameter(String.class, "name")
.addStatement("$T.out.println($S)", System.class, "hello")
.build();
TypeSpec myClass = TypeSpec.classBuilder("HelloWord")
.addModifiers(Modifier.PUBLIC)
.addMethod(spec)
.build();
try {
JavaFile javaFile = JavaFile.builder("com.example.startstudy.activity", myClass)
.addFileComment("这段代码是自动生成的不要修改!")
.build();
javaFile.writeTo(mFiler);
} catch (IOException e) {
e.printStackTrace();
}
}
}
return true;
}
@Override
public Set<String> getSupportedAnnotationTypes() {
return Collections.singleton(HelloAnnotation.class.getCanonicalName());
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
}
(4)使用注解并调用生成的类函数
@HelloAnnotation
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
HelloWorld.setName("111");
}
}
未编译前,HelloWorld.java是不存在的,这里会报错。那么,我们尝试编译一下,就会发现HelloWorld.java会自动生成,如下:
企业微信截图_15858806138763.png
// 这段代码是自动生成的不要修改!
package com.example.startstudy.activity;
import java.lang.String;
import java.lang.System;
public class HelloWord {
public static void setName(String name) {
System.out.println("hello");
}
}
这样就完成了。
知识储备:
一、注解处理器(Annotation Processor)
注解处理器(Annotation Processor)是javac的一个工具,它用来在编译时扫描和处理注解(Annotation)。你可以自定义注解,并注册相应的注解处理器(自定义的注解处理器需继承自AbstractProcessor)。
public class MyProcessor extends AbstractProcessor {
/**
* 每一个注解处理器类都必须有一个空的构造函数。
* 然而,这里有一个特殊的init()方法,它会被注解处理工具调用,并输入processingEnvironment参数。
* @param processingEnvironment 提供很多有用的工具类如Elements, Types和Filer等。
*/
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
}
/**
* 这相当于每个处理器的主函数main()。
* 你在这里写你的扫描、评估和处理注解的代码,以及生成Java文件。
* 输入参数roundEnvironment,可以让你查询出包含特定注解的被注解元素。
*/
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
return false;
}
/**
* 这里你必须指定,这个注解处理器是注册给哪个注解的。
* 注意,它的返回值是一个字符串的集合,包含本处理器想要处理的注解类型的合法全称。
*/
@Override
public Set<String> getSupportedAnnotationTypes() {
return super.getSupportedAnnotationTypes();
}
/**
* 用来指定你使用的Java版本。
* 通常这里返回SourceVersion.latestSupported()。
*/
@Override
public Set<String> getSupportedOptions() {
return super.getSupportedOptions();
}
}
二、com.google.auto.service:auto-service
Google提供了一个插件来帮助我们更方便的注册注解处理器,你只需要导入对应的依赖包,在自定义的Processor类上方添加@AutoService(Processor.class)即可。
三、com.neenbedankt.android-apt
该插件用于处理注解处理器
小结
JavaPoet为square出品,并且诸如butterknife、Dagger等著名开源框架也使用该库,可见其质量保障性和稳定性。 JavaPoet提供的api清晰明了,使用起来简单方便,功能方面也很齐全,发布了很久目前也已迭代了很多个版本,趋于稳定阶段。 运用JavaPoet预生成代码的方式,在省去我们频繁书写重复代码的同时,也避免了使用运行时反射造成的效率问题。
参考资料:
网友评论