背景
最近在研究mapStruct,而mapStruct核心技巧就是apt,透過編譯期註解+freemarker進行java檔案生成,從而省去了很多編碼。
本wiki將闡述一個apt的程式設計實踐。
實踐過程
建立一個hello工程
工程由兩個模組組成:
application模組,將使用自定義的編譯器註解
apt模組,自定義註解,並且完成AbstractProcessor的繼承和實現
根pom如下:
<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如下
<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如下
<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