JavaPoet动态生成代码,面试初级java工程师问题

  • 4

  • 5

  • 6

  • 7

build.gradle (Module:app)

apply plugin: 'com.neenbedankt.android-apt' dependencies { ... compile project(':hello-annotation') apt project(':hello-compiler') }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

build.gradle (Module:hello-compiler)

dependencies { ... compile 'com.squareup:javapoet:1.9.0' compile 'com.google.auto.service:auto-service:1.0-rc2' }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 1

  • 2

  • 3

  • 4

  • 5

注: 自Android Gradle 插件 2.2 版本开始,官方提供了名为 annotationProcessor 的功能来完全代替 android-apt。

若工程使用gradle版本>=2.2,则此处无需引用com.neenbedankt.android-apt相关,将 apt project(':hello-compiler') 改为 annotationProcessor project(':hello-compiler') 即可。

②. 定义注解: (Module:hello-annotation)

HelloAnnotation.java

@Retention(RetentionPolicy.CLASS) @Target(ElementType.TYPE) public @interface HelloAnnotation { }

  • 1

  • 2

  • 3

  • 4

  • 1

  • 2

  • 3

  • 4

③. 定义Processor: (Module:hello-compiler)

HelloProcessor.java

@AutoService(Processor.class) public class HelloProcessor extends AbstractProcessor { private Filer filer; @Override public synchronized void init(ProcessingEnvironment processingEnv) { super.init(processingEnv); filer = processingEnv.getFiler(); // for creating file } @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { for (TypeElement element : annotations) { if (element.getQualifiedName().toString().equals(HelloAnnotation.class.getCanonicalName())) { // main method MethodSpec main = MethodSpec.methodBuilder("main") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .returns(void.class) .addParameter(String[].class, "args") .addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!") .build(); // HelloWorld class TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld") .addModifiers(Modifier.PUBLIC, Modifier.FINAL) .addMethod(main) .build(); try { // build com.example.HelloWorld.java JavaFile javaFile = JavaFile.builder("com.example", helloWorld) .addFileComment(" This codes are generated automatically. Do not modify!") .build(); // write to file javaFile.writeTo(filer); } 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(); } }

  • 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

  • 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

④. 使用注解并调用生成的类函数

MainActivity.java (Module:app)

@HelloAnnotation public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); HelloWorld.main(null); } }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

未编译前,HelloWorld.java是不存在的,这里会报错。那么,我们尝试编译一下,就会发现HelloWorld.java会自动生成,如下:

// This codes are generated automatically. Do not modify! package com.example; import java.lang.String; import java.lang.System; public final class HelloWorld { public static void main(String[] args) { System.out.println("Hello, JavaPoet!"); } }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

5.2 根据协议文件生成对应代码

假设我们对类的声明以及接口的声明是以特定格式写在一个协议文件中,那么我们可以先读取该协议文件内容,使用JavaPoet根据协议对应生成Java代码。

如定义以下协议文件:

service TestDemo { rpc doRequest (MyRequest) returns (MyResponse) { // 请求接口定义 } message MyRequest { // 请求内容实体 string content; } message MyResponse { // 返回内容实体 int32 status_code; string entity; } }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

那么利用JavaPoet我们可以生成对应的TestDemo.java, MyRequest.java, MyResponse.java, 以及TestDemo.java中对应的请求接口和实现。

注:此部分协议定义参考自google开源的protobuffer和grpc

5.3 更多待扩展

六、知识储备


6.1 注解处理器(Annotation Processor)

注解处理器(Annotation Processor)是javac的一个工具,它用来在编译时扫描和处理注解(Annotation)。你可以自定义注解,并注册相应的注解处理器(自定义的注解处理器需继承自AbstractProcessor)。

6.1.1 自定义注解处理器

定义一个注解处理器,需要继承自AbstractProcessor。如下所示:

package com.example; public class MyProcessor extends AbstractProcessor { @Override public synchronized void init(ProcessingEnvironment env){ } @Override public boolean process(Set<? extends TypeElement> annoations, RoundEnvironment env) { } @Override public Set<String> getSupportedAnnotationTypes() { } @Override public SourceVersion getSupportedSourceVersion() { } }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • init(ProcessingEnvironment env): 每一个注解处理器类都必须有一个空的构造函数。然而,这里有一个特殊的init()方法,它会被注解处理工具调用,并输入ProcessingEnviroment参数。ProcessingEnviroment提供很多有用的工具类如Elements, Types和Filer等。

  • process(Set< ? extends TypeElement> annotations, RoundEnvironment env): 这相当于每个处理器的主函数main()。你在这里写你的扫描、评估和处理注解的代码,以及生成Java文件。输入参数RoundEnviroment,可以让你查询出包含特定注解的被注解元素。

  • getSupportedAnnotationTypes(): 这里你必须指定,这个注解处理器是注册给哪个注解的。注意,它的返回值是一个字符串的集合,包含本处理器想要处理的注解类型的合法全称。

  • getSupportedSourceVersion(): 用来指定你使用的Java版本。通常这里返回SourceVersion.latestSupported()。

注: 注解处理器是运行在独立的虚拟机JVM中,javac启动一个完整Java虚拟机来运行注解处理器。

6.1.2 注册注解处理器

那么,如何将我们自定义的处理器MyProcessor注册到javac中呢?首先我们需要将我们的注解处理器打包到一个jar文件中,其次在这个jar中,需要打包一个特定的文件javax.annotation.processing.Processor到META-INF/services路径下。以下是这个jar的大致结构示意图:

  • MyProcessor.jar

  • com

  • example

  • MyProcessor.jar

  • META-INF

  • services

  • javax.annotation.processing.Processor

打包进MyProcessor.jar中的javax.annotation.processing.Processor的内容是,注解处理器的合法的全名列表,每一个元素换行分割:

com.example.MyProcessor com.foo.OtherProcessor net.blabla.SpecialProcessor

  • 1

  • 2

  • 3

  • 1

  • 2

  • 3

把MyProcessor.jar放到你的builpath中,javac会自动检查和读取javax.annotation.processing.Processor中的内容,并且注册MyProcessor作为注解处理器。

6.1.3 com.google.auto.service:auto-service

Google提供了一个插件来帮助我们更方便的注册注解处理器,你只需要导入对应的依赖包,在自定义的Processor类上方添加@AutoService(Processor.class)即可。如下:

  • 导入依赖包

compile 'com.google.auto.service:auto-service:1.0-rc2'

  • 1

  • 1

  • 添加声明

@AutoService(Processor.class) public class MyProcessor extends AbstractProcessor { ... }

  • 1

  • 2

  • 3

  • 4

  • 1

  • 2

  • 3

  • 4

6.1.4 com.neenbedankt.android-apt

该插件用于处理注解处理器,用法如下:

  • 添加plugin声明:

apply plugin: 'com.neenbedankt.android-apt'

  • 1

  • 1

  • 添加classpath声明:

classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'

  • 1

  • 1

  • 添加处理声明:

小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
img

最后

学习视频:

大厂面试真题:

  • 3

  • 4

6.1.4 com.neenbedankt.android-apt

该插件用于处理注解处理器,用法如下:

  • 添加plugin声明:

apply plugin: 'com.neenbedankt.android-apt'

  • 1

  • 1

  • 添加classpath声明:

classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'

  • 1

  • 1

  • 添加处理声明:

小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-NuczktNA-1711137978642)]
[外链图片转存中…(img-5c6ut8B3-1711137978643)]
[外链图片转存中…(img-RZbTJ643-1711137978643)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
[外链图片转存中…(img-Rh8xzNDH-1711137978643)]

最后

学习视频:

[外链图片转存中…(img-kjLIrUNK-1711137978644)]

大厂面试真题:

[外链图片转存中…(img-TH11x6rN-1711137978645)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值