Skip to content

Commit ceb4fe8

Browse files
test: Add Javapoet (#1778)
* test: Add Javapoet Signed-off-by: unknowIfGuestInDream <liang.tang.cx@gmail.com> * test: Add Javapoet Signed-off-by: unknowIfGuestInDream <liang.tang.cx@gmail.com> --------- Signed-off-by: unknowIfGuestInDream <liang.tang.cx@gmail.com>
1 parent 2ad18cb commit ceb4fe8

File tree

4 files changed

+359
-0
lines changed

4 files changed

+359
-0
lines changed

core/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,11 @@
428428
<artifactId>javaluator</artifactId>
429429
<scope>provided</scope>
430430
</dependency>
431+
<dependency>
432+
<groupId>com.palantir.javapoet</groupId>
433+
<artifactId>javapoet</artifactId>
434+
<scope>test</scope>
435+
</dependency>
431436
</dependencies>
432437

433438
<build>

core/src/main/java/module-info.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
requires java.net.http;
3838
requires java.sql;
3939
requires java.xml;
40+
requires static java.compiler;
4041
requires org.apache.commons.lang3;
4142
requires javafx.controls;
4243
requires org.apache.commons.configuration2;
Lines changed: 347 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,347 @@
1+
/*
2+
* Copyright (c) 2024 unknowIfGuestInDream.
3+
* All rights reserved.
4+
*
5+
* Redistribution and use in source and binary forms, with or without
6+
* modification, are permitted provided that the following conditions are met:
7+
* * Redistributions of source code must retain the above copyright
8+
* notice, this list of conditions and the following disclaimer.
9+
* * Redistributions in binary form must reproduce the above copyright
10+
* notice, this list of conditions and the following disclaimer in the
11+
* documentation and/or other materials provided with the distribution.
12+
* * Neither the name of unknowIfGuestInDream, any associated website, nor the
13+
* names of its contributors may be used to endorse or promote products
14+
* derived from this software without specific prior written permission.
15+
*
16+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17+
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18+
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19+
* DISCLAIMED. IN NO EVENT SHALL UNKNOWIFGUESTINDREAM BE LIABLE FOR ANY
20+
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21+
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22+
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23+
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25+
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26+
*/
27+
28+
package com.tlcsdm.core.javapoet;
29+
30+
import com.palantir.javapoet.ClassName;
31+
import com.palantir.javapoet.JavaFile;
32+
import com.palantir.javapoet.MethodSpec;
33+
import com.palantir.javapoet.ParameterizedTypeName;
34+
import com.palantir.javapoet.TypeName;
35+
import com.palantir.javapoet.TypeSpec;
36+
import org.junit.jupiter.api.Test;
37+
38+
import javax.lang.model.element.Modifier;
39+
import java.io.IOException;
40+
import java.util.Collections;
41+
import java.util.Date;
42+
43+
/**
44+
* <a href="https://github.com/palantir/javapoet">官网实例</a>
45+
*
46+
* @author unknowIfGuestInDream
47+
*/
48+
public class JavapoetTest {
49+
50+
/**
51+
* 为了声明 main 方法,我们创建了一个 MethodSpec “main”,它配置了修饰符、返回类型、
52+
* 参数和代码语句。我们将 main 方法添加到 HelloWorld 类中,然后将其添加到 HelloWorld.java 文件中。
53+
* <p>
54+
* 在本例中,我们将文件写入 System.out,但我们也可以将其作为字符串 (JavaFile.toString()) 或
55+
* 将其写入文件系统 (JavaFile.writeTo())。
56+
*/
57+
@Test
58+
void testMain() throws IOException {
59+
MethodSpec main = MethodSpec.methodBuilder("main")
60+
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
61+
.returns(void.class)
62+
.addParameter(String[].class, "args")
63+
.addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!")
64+
.build();
65+
66+
print(main);
67+
}
68+
69+
/**
70+
* 不对方法和构造函数的主体进行建模。没有表达式类,没有语句类或语法树节点。
71+
* 相反,JavaPoet 使用字符串作为代码块:
72+
*
73+
* @throws IOException
74+
*/
75+
@Test
76+
void codeFlow1() throws IOException {
77+
MethodSpec main = MethodSpec.methodBuilder("main")
78+
.addCode(""
79+
+ "int total = 0;\n"
80+
+ "for (int i = 0; i < 10; i++) {\n"
81+
+ " total += i;\n"
82+
+ "}\n")
83+
.build();
84+
85+
print(main);
86+
}
87+
88+
/**
89+
* 手动分号、换行和缩进很繁琐,因此 JavaPoet 提供了 API 来简化它。
90+
* 有 addStatement() 来处理分号和换行符,
91+
* 和 beginControlFlow() + endControlFlow() 一起用于大括号、换行符和缩进:
92+
*/
93+
@Test
94+
void codeFlow2() throws IOException {
95+
MethodSpec main = MethodSpec.methodBuilder("main")
96+
.addStatement("int total = 0")
97+
.beginControlFlow("for (int i = 0; i < 10; i++)")
98+
.addStatement("total += i")
99+
.endControlFlow()
100+
.build();
101+
102+
print(main);
103+
}
104+
105+
/**
106+
* 假设我们不是简单地将 0 添加到 10,而是希望使操作和范围可配置。下面是一个生成方法的方法:
107+
*
108+
* @throws IOException
109+
*/
110+
@Test
111+
void codeFlow3() throws IOException {
112+
MethodSpec main = MethodSpec.methodBuilder("multiply10to20")
113+
.returns(int.class)
114+
.addStatement("int result = 1")
115+
.beginControlFlow("for (int i = " + "10" + "; i < " + "20" + "; i++)")
116+
.addStatement("result = result " + "*" + " i")
117+
.endControlFlow()
118+
.addStatement("return result")
119+
.build();
120+
121+
print(main);
122+
}
123+
124+
/**
125+
* 某些控制流语句(例如 if/else)可以具有无限的控制流可能性。
126+
* 您可以使用 nextControlFlow() 处理这些选项:
127+
*
128+
* @throws IOException
129+
*/
130+
@Test
131+
void codeFlow4() throws IOException {
132+
MethodSpec main = MethodSpec.methodBuilder("main")
133+
.addStatement("long now = $T.currentTimeMillis()", System.class)
134+
.beginControlFlow("if ($T.currentTimeMillis() < now)", System.class)
135+
.addStatement("$T.out.println($S)", System.class, "Time travelling, woo hoo!")
136+
.nextControlFlow("else if ($T.currentTimeMillis() == now)", System.class)
137+
.addStatement("$T.out.println($S)", System.class, "Time stood still!")
138+
.nextControlFlow("else")
139+
.addStatement("$T.out.println($S)", System.class, "Ok, time still moving forward")
140+
.endControlFlow()
141+
.build();
142+
143+
print(main);
144+
}
145+
146+
/**
147+
* 使用 try/catch 捕获异常也是 nextControlFlow() 的一个用例:
148+
*/
149+
@Test
150+
void codeFlow5() throws IOException {
151+
MethodSpec main = MethodSpec.methodBuilder("main")
152+
.beginControlFlow("try")
153+
.addStatement("throw new Exception($S)", "Failed")
154+
.nextControlFlow("catch ($T e)", Exception.class)
155+
.addStatement("throw new $T(e)", RuntimeException.class)
156+
.endControlFlow()
157+
.build();
158+
159+
print(main);
160+
}
161+
162+
/**
163+
* 对 beginControlFlow() 和 addStatement 的调用中的字符串连接会分散注意力。
164+
* 运算符太多。为了解决这个问题,JavaPoet 提供了一种受 String.format() 启发但不兼容的语法。
165+
* 它接受 $L 在输出中发出 Literal 值。这就像 Formatter 的 %s 一样:
166+
* <p>
167+
* 文本直接发出到输出代码,无需转义。文本的参数可以是字符串,
168+
* 原语和一些 JavaPoet 类型。
169+
*
170+
* @throws IOException
171+
*/
172+
@Test
173+
void literals() throws IOException {
174+
MethodSpec main = MethodSpec.methodBuilder("main")
175+
.returns(int.class)
176+
.addStatement("int result = 0")
177+
.beginControlFlow("for (int i = $L; i < $L; i++)", 1, 10)
178+
.addStatement("result = result $L i", "*")
179+
.endControlFlow()
180+
.addStatement("return result")
181+
.build();
182+
print(main);
183+
}
184+
185+
/**
186+
* 当发出包含字符串文字的代码时,我们可以使用 $S 来发出一个字符串,并带有换行引号
187+
* 标记和转义。这是一个发出 3 个方法的程序,每个方法都返回自己的名称:
188+
*
189+
* @throws IOException
190+
*/
191+
@Test
192+
void strings1() throws IOException {
193+
TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
194+
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
195+
.addMethod(whatsMyName("slimShady"))
196+
.addMethod(whatsMyName("eminem"))
197+
.addMethod(whatsMyName("marshallMathers"))
198+
.build();
199+
200+
JavaFile javaFile = JavaFile.builder("com.example.helloworld", helloWorld)
201+
.build();
202+
203+
javaFile.writeTo(System.out);
204+
}
205+
206+
private MethodSpec whatsMyName(String name) {
207+
return MethodSpec.methodBuilder(name)
208+
.returns(String.class)
209+
.addStatement("return $S", name)
210+
.build();
211+
}
212+
213+
/**
214+
* 我们 Java 程序员喜欢我们的类型:它们使我们的代码更容易理解。JavaPoet 也加入了进来。
215+
* 它内置了丰富的类型支持,包括自动生成 import 语句。只需使用 $T 来引用类型:
216+
*
217+
* @throws IOException
218+
*/
219+
@Test
220+
void types() throws IOException {
221+
MethodSpec today = MethodSpec.methodBuilder("today")
222+
.returns(Date.class)
223+
.addStatement("return new $T()", Date.class)
224+
.build();
225+
226+
TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
227+
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
228+
.addMethod(today)
229+
.build();
230+
231+
JavaFile javaFile = JavaFile.builder("com.example.helloworld", helloWorld)
232+
.build();
233+
234+
javaFile.writeTo(System.out);
235+
}
236+
237+
/**
238+
* 我们传递了 Date.class 来引用一个类,该类恰好在我们生成代码时可用。
239+
* 情况并非如此。下面是一个类似的示例,但此示例引用了一个尚不存在的类:
240+
*
241+
* @throws IOException
242+
*/
243+
@Test
244+
void types1() throws IOException {
245+
ClassName hoverboard = ClassName.get("com.mattel", "Hoverboard");
246+
247+
MethodSpec today = MethodSpec.methodBuilder("tomorrow")
248+
.returns(hoverboard)
249+
.addStatement("return new $T()", hoverboard)
250+
.build();
251+
252+
print(today);
253+
}
254+
255+
/**
256+
* ClassName 类型非常重要,在使用 JavaPoet 时,您将经常需要它。
257+
* 它可以识别任何声明的类。声明类型只是 Java 丰富类型系统的开始:
258+
* 我们还有数组、参数化类型、通配符类型和类型变量。JavaPoet 具有用于构建以下每个类的类:
259+
*
260+
* @throws IOException
261+
*/
262+
@Test
263+
void types2() throws IOException {
264+
ClassName hoverboard = ClassName.get("com.mattel", "Hoverboard");
265+
ClassName list = ClassName.get("java.util", "List");
266+
ClassName arrayList = ClassName.get("java.util", "ArrayList");
267+
TypeName listOfHoverboards = ParameterizedTypeName.get(list, hoverboard);
268+
269+
MethodSpec beyond = MethodSpec.methodBuilder("beyond")
270+
.returns(listOfHoverboards)
271+
.addStatement("$T result = new $T<>()", listOfHoverboards, arrayList)
272+
.addStatement("result.add(new $T())", hoverboard)
273+
.addStatement("result.add(new $T())", hoverboard)
274+
.addStatement("result.add(new $T())", hoverboard)
275+
.addStatement("return result")
276+
.build();
277+
278+
print(beyond);
279+
}
280+
281+
/**
282+
* JavaPoet 支持 import static。它通过显式收集类型成员名称来实现这一点。
283+
* 让我们用一些静态糖来增强前面的例子:
284+
*
285+
* @throws IOException
286+
*/
287+
@Test
288+
void types3() throws IOException {
289+
ClassName namedBoards = ClassName.get("com.mattel", "Hoverboard", "Boards");
290+
ClassName hoverboard = ClassName.get("com.mattel", "Hoverboard");
291+
292+
MethodSpec main = MethodSpec.methodBuilder("tomorrow")
293+
.returns(hoverboard)
294+
.addStatement("return new $T()", hoverboard)
295+
.build();
296+
297+
TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
298+
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
299+
.addMethod(main)
300+
.build();
301+
302+
JavaFile javaFile = JavaFile.builder("com.example.helloworld", helloWorld)
303+
.addStaticImport(hoverboard, "createNimbus")
304+
.addStaticImport(namedBoards, "*")
305+
.addStaticImport(Collections.class, "*")
306+
.build();
307+
javaFile.writeTo(System.out);
308+
}
309+
310+
/**
311+
* 生成的代码通常是自引用的。使用 $N 按名称引用另一个生成的声明。
312+
* 这是一个调用另一个方法的方法:
313+
*
314+
* @throws IOException
315+
*/
316+
@Test
317+
void names() throws IOException {
318+
MethodSpec hexDigit = MethodSpec.methodBuilder("hexDigit")
319+
.addParameter(int.class, "i")
320+
.returns(char.class)
321+
.addStatement("return (char) (i < 10 ? i + '0' : i - 10 + 'a')")
322+
.build();
323+
324+
MethodSpec byteToHex = MethodSpec.methodBuilder("byteToHex")
325+
.addParameter(int.class, "b")
326+
.returns(String.class)
327+
.addStatement("char[] result = new char[2]")
328+
.addStatement("result[0] = $N((b >>> 4) & 0xf)", hexDigit)
329+
.addStatement("result[1] = $N(b & 0xf)", hexDigit)
330+
.addStatement("return new String(result)")
331+
.build();
332+
333+
print(byteToHex);
334+
}
335+
336+
private void print(MethodSpec main) throws IOException {
337+
TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
338+
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
339+
.addMethod(main)
340+
.build();
341+
342+
JavaFile javaFile = JavaFile.builder("com.example.helloworld", helloWorld)
343+
.build();
344+
345+
javaFile.writeTo(System.out);
346+
}
347+
}

pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@
186186
<jmh.version>1.37</jmh.version>
187187
<jtidy.version>1.0.5</jtidy.version>
188188
<javaluator.version>3.0.5</javaluator.version>
189+
<javapoet.version>0.5.0</javapoet.version>
189190
</properties>
190191

191192
<issueManagement>
@@ -1180,6 +1181,11 @@
11801181
<artifactId>javaluator</artifactId>
11811182
<version>${javaluator.version}</version>
11821183
</dependency>
1184+
<dependency>
1185+
<groupId>com.palantir.javapoet</groupId>
1186+
<artifactId>javapoet</artifactId>
1187+
<version>${javapoet.version}</version>
1188+
</dependency>
11831189
</dependencies>
11841190
</dependencyManagement>
11851191

0 commit comments

Comments
 (0)