java-apt编程实践(Annotatino Processing Tool+maven)

背景
最近在研究mapStruct,而mapStruct核心技巧就是apt,通过编译期注解+freemarker进行java文件生成,从而省去了很多编码。
本wiki将阐述一个apt的编程实践。

实践过程
创建一个hello工程
工程由两个模块组成:

application模块,将使用自定义的编译器注解
apt模块,自定义注解,并且完成AbstractProcessor的继承和实现
根pom如下:


4.0.0

<groupId>com.mine</groupId>
<artifactId>apt-test</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
    <module>application</module>
    <module>apt</module>
</modules>
<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.version>1.8</java.version>
</properties>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
application的pom如下



apt-test
com.mine
1.0-SNAPSHOT

4.0.0

<artifactId>application</artifactId>
<dependencies>
    <dependency>
        <groupId>com.mine</groupId>
        <artifactId>apt</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.12</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

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
apt的pom如下



apt-test
com.mine
1.0-SNAPSHOT

4.0.0

<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>

<artifactId>apt</artifactId>
<build>
    <plugins>
        <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>2.5.1</version>
            <configuration>
                <source>1.7</source>
                <target>1.7</target>
                <compilerArgument>-proc:none</compilerArgument>
            </configuration>
        </plugin>
    </plugins>
</build>

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

创建一个Main类,并且运行一下看看结果

编写apt代码
自定义一个注解

实现AbstractProcessor,实现process过程

package com.mine.processor;

import com.mine.anno.CustomAnnotation;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.JavaFileObject;
import java.io.IOException;
import java.io.Writer;
import java.util.Set;

@SupportedAnnotationTypes({
"com.mine.anno.CustomAnnotation"
})
public class MyProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
//然后文件会被解释为.class文件

    StringBuilder builder = new StringBuilder()
            .append("package com.mine.annotationprocessor.generated;\n\n")
            .append("public class GeneratedClass {\n\n")
            .append("\tpublic String getMessage() {\n")
            .append("\t\treturn \"");

    //获取所有被CustomAnnotation修饰的代码元素
    for (Element element : roundEnv.getElementsAnnotatedWith(CustomAnnotation.class)) {
        String objectType = element.getSimpleName().toString();
        builder.append(objectType).append(" exists!\\n");
    }

    builder.append("\";\n")
            .append("\t}\n")
            .append("}\n");

    try {
        JavaFileObject source = processingEnv.getFiler().createSourceFile(
                "com.mine.annotationprocessor.generated.GeneratedClass");

        Writer writer = source.openWriter();
        writer.write(builder.toString());
        writer.flush();
        writer.close();
    } catch (IOException e) {
        //
    }
    return false;
}

}

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
过程很简单,通过StringBuilder来写一个java文件

配置resources
在resources/META-INF/services/创建javax.annotation.processing.Processor
内容为:
com.mine.processor.MyProcessor

这里表示,java compile编译器会通过配置文件去找到对应的processor,进行编译期的调用

编写application代码
创建一个DemoClass类

package com.mine;

import com.mine.anno.CustomAnnotation;

// 使用我们自定义的注解
@CustomAnnotation
public class DemoClass {

}
1
2
3
4
5
6
7
8
9
创建一个MyModel类

package com.mine;

import lombok.Data;

// 使用lombok的Data,这里也可以自动生成代码
@Data
public class MyModel {
private String name;
private Integer age;
}
1
2
3
4
5
6
7
8
9
10
编译
在根目录执行
mvn compile
或者直接使用idea执行

查看class字节码文件的生成情况

可以看到已经有我们生成的代码了

MyModel使用了lombok,可以自动生成get set和toString等方法

评价
通过apt可以生成很多方便的代码生成模板,比如mapStruct,lombok等。可以参考博主的其他博客查看mapStruct的使用。
————————————————

                        版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/wangjie5540/article/details/105365717

posted @   自在现实  阅读(65)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示