xref: /aosp_15_r20/external/javapoet/README.md (revision 53ff1f6b77a38363a61ff037dc7178de5baa7db4)
1*53ff1f6bSSadaf EbrahimiJavaPoet
2*53ff1f6bSSadaf Ebrahimi========
3*53ff1f6bSSadaf Ebrahimi
4*53ff1f6bSSadaf Ebrahimi`JavaPoet` is a Java API for generating `.java` source files.
5*53ff1f6bSSadaf Ebrahimi
6*53ff1f6bSSadaf EbrahimiSource file generation can be useful when doing things such as annotation processing or interacting
7*53ff1f6bSSadaf Ebrahimiwith metadata files (e.g., database schemas, protocol formats). By generating code, you eliminate
8*53ff1f6bSSadaf Ebrahimithe need to write boilerplate while also keeping a single source of truth for the metadata.
9*53ff1f6bSSadaf Ebrahimi
10*53ff1f6bSSadaf Ebrahimi
11*53ff1f6bSSadaf Ebrahimi### Example
12*53ff1f6bSSadaf Ebrahimi
13*53ff1f6bSSadaf EbrahimiHere's a (boring) `HelloWorld` class:
14*53ff1f6bSSadaf Ebrahimi
15*53ff1f6bSSadaf Ebrahimi```java
16*53ff1f6bSSadaf Ebrahimipackage com.example.helloworld;
17*53ff1f6bSSadaf Ebrahimi
18*53ff1f6bSSadaf Ebrahimipublic final class HelloWorld {
19*53ff1f6bSSadaf Ebrahimi  public static void main(String[] args) {
20*53ff1f6bSSadaf Ebrahimi    System.out.println("Hello, JavaPoet!");
21*53ff1f6bSSadaf Ebrahimi  }
22*53ff1f6bSSadaf Ebrahimi}
23*53ff1f6bSSadaf Ebrahimi```
24*53ff1f6bSSadaf Ebrahimi
25*53ff1f6bSSadaf EbrahimiAnd this is the (exciting) code to generate it with JavaPoet:
26*53ff1f6bSSadaf Ebrahimi
27*53ff1f6bSSadaf Ebrahimi```java
28*53ff1f6bSSadaf EbrahimiMethodSpec main = MethodSpec.methodBuilder("main")
29*53ff1f6bSSadaf Ebrahimi    .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
30*53ff1f6bSSadaf Ebrahimi    .returns(void.class)
31*53ff1f6bSSadaf Ebrahimi    .addParameter(String[].class, "args")
32*53ff1f6bSSadaf Ebrahimi    .addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!")
33*53ff1f6bSSadaf Ebrahimi    .build();
34*53ff1f6bSSadaf Ebrahimi
35*53ff1f6bSSadaf EbrahimiTypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
36*53ff1f6bSSadaf Ebrahimi    .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
37*53ff1f6bSSadaf Ebrahimi    .addMethod(main)
38*53ff1f6bSSadaf Ebrahimi    .build();
39*53ff1f6bSSadaf Ebrahimi
40*53ff1f6bSSadaf EbrahimiJavaFile javaFile = JavaFile.builder("com.example.helloworld", helloWorld)
41*53ff1f6bSSadaf Ebrahimi    .build();
42*53ff1f6bSSadaf Ebrahimi
43*53ff1f6bSSadaf EbrahimijavaFile.writeTo(System.out);
44*53ff1f6bSSadaf Ebrahimi```
45*53ff1f6bSSadaf Ebrahimi
46*53ff1f6bSSadaf EbrahimiTo declare the main method, we've created a `MethodSpec` "main" configured with modifiers, return
47*53ff1f6bSSadaf Ebrahimitype, parameters and code statements. We add the main method to a `HelloWorld` class, and then add
48*53ff1f6bSSadaf Ebrahimithat to a `HelloWorld.java` file.
49*53ff1f6bSSadaf Ebrahimi
50*53ff1f6bSSadaf EbrahimiIn this case we write the file to `System.out`, but we could also get it as a string
51*53ff1f6bSSadaf Ebrahimi(`JavaFile.toString()`) or write it to the file system (`JavaFile.writeTo()`).
52*53ff1f6bSSadaf Ebrahimi
53*53ff1f6bSSadaf EbrahimiThe [Javadoc][javadoc] catalogs the complete JavaPoet API, which we explore below.
54*53ff1f6bSSadaf Ebrahimi
55*53ff1f6bSSadaf Ebrahimi### Code & Control Flow
56*53ff1f6bSSadaf Ebrahimi
57*53ff1f6bSSadaf EbrahimiMost of JavaPoet's API uses plain old immutable Java objects. There's also builders, method chaining
58*53ff1f6bSSadaf Ebrahimiand varargs to make the API friendly. JavaPoet offers models for classes & interfaces (`TypeSpec`),
59*53ff1f6bSSadaf Ebrahimifields (`FieldSpec`), methods & constructors (`MethodSpec`), parameters (`ParameterSpec`) and
60*53ff1f6bSSadaf Ebrahimiannotations (`AnnotationSpec`).
61*53ff1f6bSSadaf Ebrahimi
62*53ff1f6bSSadaf EbrahimiBut the _body_ of methods and constructors is not modeled. There's no expression class, no
63*53ff1f6bSSadaf Ebrahimistatement class or syntax tree nodes. Instead, JavaPoet uses strings for code blocks:
64*53ff1f6bSSadaf Ebrahimi
65*53ff1f6bSSadaf Ebrahimi```java
66*53ff1f6bSSadaf EbrahimiMethodSpec main = MethodSpec.methodBuilder("main")
67*53ff1f6bSSadaf Ebrahimi    .addCode(""
68*53ff1f6bSSadaf Ebrahimi        + "int total = 0;\n"
69*53ff1f6bSSadaf Ebrahimi        + "for (int i = 0; i < 10; i++) {\n"
70*53ff1f6bSSadaf Ebrahimi        + "  total += i;\n"
71*53ff1f6bSSadaf Ebrahimi        + "}\n")
72*53ff1f6bSSadaf Ebrahimi    .build();
73*53ff1f6bSSadaf Ebrahimi```
74*53ff1f6bSSadaf Ebrahimi
75*53ff1f6bSSadaf EbrahimiWhich generates this:
76*53ff1f6bSSadaf Ebrahimi
77*53ff1f6bSSadaf Ebrahimi```java
78*53ff1f6bSSadaf Ebrahimivoid main() {
79*53ff1f6bSSadaf Ebrahimi  int total = 0;
80*53ff1f6bSSadaf Ebrahimi  for (int i = 0; i < 10; i++) {
81*53ff1f6bSSadaf Ebrahimi    total += i;
82*53ff1f6bSSadaf Ebrahimi  }
83*53ff1f6bSSadaf Ebrahimi}
84*53ff1f6bSSadaf Ebrahimi```
85*53ff1f6bSSadaf Ebrahimi
86*53ff1f6bSSadaf EbrahimiThe manual semicolons, line wrapping, and indentation are tedious and so JavaPoet offers APIs to
87*53ff1f6bSSadaf Ebrahimimake it easier. There's `addStatement()` which takes care of semicolons and newline, and
88*53ff1f6bSSadaf Ebrahimi`beginControlFlow()` + `endControlFlow()` which are used together for braces, newlines, and
89*53ff1f6bSSadaf Ebrahimiindentation:
90*53ff1f6bSSadaf Ebrahimi
91*53ff1f6bSSadaf Ebrahimi```java
92*53ff1f6bSSadaf EbrahimiMethodSpec main = MethodSpec.methodBuilder("main")
93*53ff1f6bSSadaf Ebrahimi    .addStatement("int total = 0")
94*53ff1f6bSSadaf Ebrahimi    .beginControlFlow("for (int i = 0; i < 10; i++)")
95*53ff1f6bSSadaf Ebrahimi    .addStatement("total += i")
96*53ff1f6bSSadaf Ebrahimi    .endControlFlow()
97*53ff1f6bSSadaf Ebrahimi    .build();
98*53ff1f6bSSadaf Ebrahimi```
99*53ff1f6bSSadaf Ebrahimi
100*53ff1f6bSSadaf EbrahimiThis example is lame because the generated code is constant! Suppose instead of just adding 0 to 10,
101*53ff1f6bSSadaf Ebrahimiwe want to make the operation and range configurable. Here's a method that generates a method:
102*53ff1f6bSSadaf Ebrahimi
103*53ff1f6bSSadaf Ebrahimi```java
104*53ff1f6bSSadaf Ebrahimiprivate MethodSpec computeRange(String name, int from, int to, String op) {
105*53ff1f6bSSadaf Ebrahimi  return MethodSpec.methodBuilder(name)
106*53ff1f6bSSadaf Ebrahimi      .returns(int.class)
107*53ff1f6bSSadaf Ebrahimi      .addStatement("int result = 1")
108*53ff1f6bSSadaf Ebrahimi      .beginControlFlow("for (int i = " + from + "; i < " + to + "; i++)")
109*53ff1f6bSSadaf Ebrahimi      .addStatement("result = result " + op + " i")
110*53ff1f6bSSadaf Ebrahimi      .endControlFlow()
111*53ff1f6bSSadaf Ebrahimi      .addStatement("return result")
112*53ff1f6bSSadaf Ebrahimi      .build();
113*53ff1f6bSSadaf Ebrahimi}
114*53ff1f6bSSadaf Ebrahimi```
115*53ff1f6bSSadaf Ebrahimi
116*53ff1f6bSSadaf EbrahimiAnd here's what we get when we call `computeRange("multiply10to20", 10, 20, "*")`:
117*53ff1f6bSSadaf Ebrahimi
118*53ff1f6bSSadaf Ebrahimi```java
119*53ff1f6bSSadaf Ebrahimiint multiply10to20() {
120*53ff1f6bSSadaf Ebrahimi  int result = 1;
121*53ff1f6bSSadaf Ebrahimi  for (int i = 10; i < 20; i++) {
122*53ff1f6bSSadaf Ebrahimi    result = result * i;
123*53ff1f6bSSadaf Ebrahimi  }
124*53ff1f6bSSadaf Ebrahimi  return result;
125*53ff1f6bSSadaf Ebrahimi}
126*53ff1f6bSSadaf Ebrahimi```
127*53ff1f6bSSadaf Ebrahimi
128*53ff1f6bSSadaf EbrahimiMethods generating methods! And since JavaPoet generates source instead of bytecode, you can
129*53ff1f6bSSadaf Ebrahimiread through it to make sure it's right.
130*53ff1f6bSSadaf Ebrahimi
131*53ff1f6bSSadaf EbrahimiSome control flow statements, such as `if/else`, can have unlimited control flow possibilities.
132*53ff1f6bSSadaf EbrahimiYou can handle those options using `nextControlFlow()`:
133*53ff1f6bSSadaf Ebrahimi
134*53ff1f6bSSadaf Ebrahimi```java
135*53ff1f6bSSadaf EbrahimiMethodSpec main = MethodSpec.methodBuilder("main")
136*53ff1f6bSSadaf Ebrahimi    .addStatement("long now = $T.currentTimeMillis()", System.class)
137*53ff1f6bSSadaf Ebrahimi    .beginControlFlow("if ($T.currentTimeMillis() < now)", System.class)
138*53ff1f6bSSadaf Ebrahimi    .addStatement("$T.out.println($S)", System.class, "Time travelling, woo hoo!")
139*53ff1f6bSSadaf Ebrahimi    .nextControlFlow("else if ($T.currentTimeMillis() == now)", System.class)
140*53ff1f6bSSadaf Ebrahimi    .addStatement("$T.out.println($S)", System.class, "Time stood still!")
141*53ff1f6bSSadaf Ebrahimi    .nextControlFlow("else")
142*53ff1f6bSSadaf Ebrahimi    .addStatement("$T.out.println($S)", System.class, "Ok, time still moving forward")
143*53ff1f6bSSadaf Ebrahimi    .endControlFlow()
144*53ff1f6bSSadaf Ebrahimi    .build();
145*53ff1f6bSSadaf Ebrahimi```
146*53ff1f6bSSadaf Ebrahimi
147*53ff1f6bSSadaf EbrahimiWhich generates:
148*53ff1f6bSSadaf Ebrahimi
149*53ff1f6bSSadaf Ebrahimi```java
150*53ff1f6bSSadaf Ebrahimivoid main() {
151*53ff1f6bSSadaf Ebrahimi  long now = System.currentTimeMillis();
152*53ff1f6bSSadaf Ebrahimi  if (System.currentTimeMillis() < now)  {
153*53ff1f6bSSadaf Ebrahimi    System.out.println("Time travelling, woo hoo!");
154*53ff1f6bSSadaf Ebrahimi  } else if (System.currentTimeMillis() == now) {
155*53ff1f6bSSadaf Ebrahimi    System.out.println("Time stood still!");
156*53ff1f6bSSadaf Ebrahimi  } else {
157*53ff1f6bSSadaf Ebrahimi    System.out.println("Ok, time still moving forward");
158*53ff1f6bSSadaf Ebrahimi  }
159*53ff1f6bSSadaf Ebrahimi}
160*53ff1f6bSSadaf Ebrahimi```
161*53ff1f6bSSadaf Ebrahimi
162*53ff1f6bSSadaf EbrahimiCatching exceptions using `try/catch` is also a use case for `nextControlFlow()`:
163*53ff1f6bSSadaf Ebrahimi
164*53ff1f6bSSadaf Ebrahimi```java
165*53ff1f6bSSadaf EbrahimiMethodSpec main = MethodSpec.methodBuilder("main")
166*53ff1f6bSSadaf Ebrahimi    .beginControlFlow("try")
167*53ff1f6bSSadaf Ebrahimi    .addStatement("throw new Exception($S)", "Failed")
168*53ff1f6bSSadaf Ebrahimi    .nextControlFlow("catch ($T e)", Exception.class)
169*53ff1f6bSSadaf Ebrahimi    .addStatement("throw new $T(e)", RuntimeException.class)
170*53ff1f6bSSadaf Ebrahimi    .endControlFlow()
171*53ff1f6bSSadaf Ebrahimi    .build();
172*53ff1f6bSSadaf Ebrahimi```
173*53ff1f6bSSadaf Ebrahimi
174*53ff1f6bSSadaf EbrahimiWhich produces:
175*53ff1f6bSSadaf Ebrahimi
176*53ff1f6bSSadaf Ebrahimi```java
177*53ff1f6bSSadaf Ebrahimivoid main() {
178*53ff1f6bSSadaf Ebrahimi  try {
179*53ff1f6bSSadaf Ebrahimi    throw new Exception("Failed");
180*53ff1f6bSSadaf Ebrahimi  } catch (Exception e) {
181*53ff1f6bSSadaf Ebrahimi    throw new RuntimeException(e);
182*53ff1f6bSSadaf Ebrahimi  }
183*53ff1f6bSSadaf Ebrahimi}
184*53ff1f6bSSadaf Ebrahimi```
185*53ff1f6bSSadaf Ebrahimi
186*53ff1f6bSSadaf Ebrahimi### $L for Literals
187*53ff1f6bSSadaf Ebrahimi
188*53ff1f6bSSadaf EbrahimiThe string-concatenation in calls to `beginControlFlow()` and `addStatement` is distracting. Too
189*53ff1f6bSSadaf Ebrahimimany operators. To address this, JavaPoet offers a syntax inspired-by but incompatible-with
190*53ff1f6bSSadaf Ebrahimi[`String.format()`][formatter]. It accepts **`$L`** to emit a **literal** value in the output. This
191*53ff1f6bSSadaf Ebrahimiworks just like `Formatter`'s `%s`:
192*53ff1f6bSSadaf Ebrahimi
193*53ff1f6bSSadaf Ebrahimi```java
194*53ff1f6bSSadaf Ebrahimiprivate MethodSpec computeRange(String name, int from, int to, String op) {
195*53ff1f6bSSadaf Ebrahimi  return MethodSpec.methodBuilder(name)
196*53ff1f6bSSadaf Ebrahimi      .returns(int.class)
197*53ff1f6bSSadaf Ebrahimi      .addStatement("int result = 0")
198*53ff1f6bSSadaf Ebrahimi      .beginControlFlow("for (int i = $L; i < $L; i++)", from, to)
199*53ff1f6bSSadaf Ebrahimi      .addStatement("result = result $L i", op)
200*53ff1f6bSSadaf Ebrahimi      .endControlFlow()
201*53ff1f6bSSadaf Ebrahimi      .addStatement("return result")
202*53ff1f6bSSadaf Ebrahimi      .build();
203*53ff1f6bSSadaf Ebrahimi}
204*53ff1f6bSSadaf Ebrahimi```
205*53ff1f6bSSadaf Ebrahimi
206*53ff1f6bSSadaf EbrahimiLiterals are emitted directly to the output code with no escaping. Arguments for literals may be
207*53ff1f6bSSadaf Ebrahimistrings, primitives, and a few JavaPoet types described below.
208*53ff1f6bSSadaf Ebrahimi
209*53ff1f6bSSadaf Ebrahimi### $S for Strings
210*53ff1f6bSSadaf Ebrahimi
211*53ff1f6bSSadaf EbrahimiWhen emitting code that includes string literals, we can use **`$S`** to emit a **string**, complete
212*53ff1f6bSSadaf Ebrahimiwith wrapping quotation marks and escaping. Here's a program that emits 3 methods, each of which
213*53ff1f6bSSadaf Ebrahimireturns its own name:
214*53ff1f6bSSadaf Ebrahimi
215*53ff1f6bSSadaf Ebrahimi```java
216*53ff1f6bSSadaf Ebrahimipublic static void main(String[] args) throws Exception {
217*53ff1f6bSSadaf Ebrahimi  TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
218*53ff1f6bSSadaf Ebrahimi      .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
219*53ff1f6bSSadaf Ebrahimi      .addMethod(whatsMyName("slimShady"))
220*53ff1f6bSSadaf Ebrahimi      .addMethod(whatsMyName("eminem"))
221*53ff1f6bSSadaf Ebrahimi      .addMethod(whatsMyName("marshallMathers"))
222*53ff1f6bSSadaf Ebrahimi      .build();
223*53ff1f6bSSadaf Ebrahimi
224*53ff1f6bSSadaf Ebrahimi  JavaFile javaFile = JavaFile.builder("com.example.helloworld", helloWorld)
225*53ff1f6bSSadaf Ebrahimi      .build();
226*53ff1f6bSSadaf Ebrahimi
227*53ff1f6bSSadaf Ebrahimi  javaFile.writeTo(System.out);
228*53ff1f6bSSadaf Ebrahimi}
229*53ff1f6bSSadaf Ebrahimi
230*53ff1f6bSSadaf Ebrahimiprivate static MethodSpec whatsMyName(String name) {
231*53ff1f6bSSadaf Ebrahimi  return MethodSpec.methodBuilder(name)
232*53ff1f6bSSadaf Ebrahimi      .returns(String.class)
233*53ff1f6bSSadaf Ebrahimi      .addStatement("return $S", name)
234*53ff1f6bSSadaf Ebrahimi      .build();
235*53ff1f6bSSadaf Ebrahimi}
236*53ff1f6bSSadaf Ebrahimi```
237*53ff1f6bSSadaf Ebrahimi
238*53ff1f6bSSadaf EbrahimiIn this case, using `$S` gives us quotation marks:
239*53ff1f6bSSadaf Ebrahimi
240*53ff1f6bSSadaf Ebrahimi```java
241*53ff1f6bSSadaf Ebrahimipublic final class HelloWorld {
242*53ff1f6bSSadaf Ebrahimi  String slimShady() {
243*53ff1f6bSSadaf Ebrahimi    return "slimShady";
244*53ff1f6bSSadaf Ebrahimi  }
245*53ff1f6bSSadaf Ebrahimi
246*53ff1f6bSSadaf Ebrahimi  String eminem() {
247*53ff1f6bSSadaf Ebrahimi    return "eminem";
248*53ff1f6bSSadaf Ebrahimi  }
249*53ff1f6bSSadaf Ebrahimi
250*53ff1f6bSSadaf Ebrahimi  String marshallMathers() {
251*53ff1f6bSSadaf Ebrahimi    return "marshallMathers";
252*53ff1f6bSSadaf Ebrahimi  }
253*53ff1f6bSSadaf Ebrahimi}
254*53ff1f6bSSadaf Ebrahimi```
255*53ff1f6bSSadaf Ebrahimi
256*53ff1f6bSSadaf Ebrahimi### $T for Types
257*53ff1f6bSSadaf Ebrahimi
258*53ff1f6bSSadaf EbrahimiWe Java programmers love our types: they make our code easier to understand. And JavaPoet is on
259*53ff1f6bSSadaf Ebrahimiboard. It has rich built-in support for types, including automatic generation of `import`
260*53ff1f6bSSadaf Ebrahimistatements. Just use **`$T`** to reference **types**:
261*53ff1f6bSSadaf Ebrahimi
262*53ff1f6bSSadaf Ebrahimi```java
263*53ff1f6bSSadaf EbrahimiMethodSpec today = MethodSpec.methodBuilder("today")
264*53ff1f6bSSadaf Ebrahimi    .returns(Date.class)
265*53ff1f6bSSadaf Ebrahimi    .addStatement("return new $T()", Date.class)
266*53ff1f6bSSadaf Ebrahimi    .build();
267*53ff1f6bSSadaf Ebrahimi
268*53ff1f6bSSadaf EbrahimiTypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
269*53ff1f6bSSadaf Ebrahimi    .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
270*53ff1f6bSSadaf Ebrahimi    .addMethod(today)
271*53ff1f6bSSadaf Ebrahimi    .build();
272*53ff1f6bSSadaf Ebrahimi
273*53ff1f6bSSadaf EbrahimiJavaFile javaFile = JavaFile.builder("com.example.helloworld", helloWorld)
274*53ff1f6bSSadaf Ebrahimi    .build();
275*53ff1f6bSSadaf Ebrahimi
276*53ff1f6bSSadaf EbrahimijavaFile.writeTo(System.out);
277*53ff1f6bSSadaf Ebrahimi```
278*53ff1f6bSSadaf Ebrahimi
279*53ff1f6bSSadaf EbrahimiThat generates the following `.java` file, complete with the necessary `import`:
280*53ff1f6bSSadaf Ebrahimi
281*53ff1f6bSSadaf Ebrahimi```java
282*53ff1f6bSSadaf Ebrahimipackage com.example.helloworld;
283*53ff1f6bSSadaf Ebrahimi
284*53ff1f6bSSadaf Ebrahimiimport java.util.Date;
285*53ff1f6bSSadaf Ebrahimi
286*53ff1f6bSSadaf Ebrahimipublic final class HelloWorld {
287*53ff1f6bSSadaf Ebrahimi  Date today() {
288*53ff1f6bSSadaf Ebrahimi    return new Date();
289*53ff1f6bSSadaf Ebrahimi  }
290*53ff1f6bSSadaf Ebrahimi}
291*53ff1f6bSSadaf Ebrahimi```
292*53ff1f6bSSadaf Ebrahimi
293*53ff1f6bSSadaf EbrahimiWe passed `Date.class` to reference a class that just-so-happens to be available when we're
294*53ff1f6bSSadaf Ebrahimigenerating code. This doesn't need to be the case. Here's a similar example, but this one
295*53ff1f6bSSadaf Ebrahimireferences a class that doesn't exist (yet):
296*53ff1f6bSSadaf Ebrahimi
297*53ff1f6bSSadaf Ebrahimi```java
298*53ff1f6bSSadaf EbrahimiClassName hoverboard = ClassName.get("com.mattel", "Hoverboard");
299*53ff1f6bSSadaf Ebrahimi
300*53ff1f6bSSadaf EbrahimiMethodSpec today = MethodSpec.methodBuilder("tomorrow")
301*53ff1f6bSSadaf Ebrahimi    .returns(hoverboard)
302*53ff1f6bSSadaf Ebrahimi    .addStatement("return new $T()", hoverboard)
303*53ff1f6bSSadaf Ebrahimi    .build();
304*53ff1f6bSSadaf Ebrahimi```
305*53ff1f6bSSadaf Ebrahimi
306*53ff1f6bSSadaf EbrahimiAnd that not-yet-existent class is imported as well:
307*53ff1f6bSSadaf Ebrahimi
308*53ff1f6bSSadaf Ebrahimi```java
309*53ff1f6bSSadaf Ebrahimipackage com.example.helloworld;
310*53ff1f6bSSadaf Ebrahimi
311*53ff1f6bSSadaf Ebrahimiimport com.mattel.Hoverboard;
312*53ff1f6bSSadaf Ebrahimi
313*53ff1f6bSSadaf Ebrahimipublic final class HelloWorld {
314*53ff1f6bSSadaf Ebrahimi  Hoverboard tomorrow() {
315*53ff1f6bSSadaf Ebrahimi    return new Hoverboard();
316*53ff1f6bSSadaf Ebrahimi  }
317*53ff1f6bSSadaf Ebrahimi}
318*53ff1f6bSSadaf Ebrahimi```
319*53ff1f6bSSadaf Ebrahimi
320*53ff1f6bSSadaf EbrahimiThe `ClassName` type is very important, and you'll need it frequently when you're using JavaPoet.
321*53ff1f6bSSadaf EbrahimiIt can identify any _declared_ class. Declared types are just the beginning of Java's rich type
322*53ff1f6bSSadaf Ebrahimisystem: we also have arrays, parameterized types, wildcard types, and type variables. JavaPoet has
323*53ff1f6bSSadaf Ebrahimiclasses for building each of these:
324*53ff1f6bSSadaf Ebrahimi
325*53ff1f6bSSadaf Ebrahimi```java
326*53ff1f6bSSadaf EbrahimiClassName hoverboard = ClassName.get("com.mattel", "Hoverboard");
327*53ff1f6bSSadaf EbrahimiClassName list = ClassName.get("java.util", "List");
328*53ff1f6bSSadaf EbrahimiClassName arrayList = ClassName.get("java.util", "ArrayList");
329*53ff1f6bSSadaf EbrahimiTypeName listOfHoverboards = ParameterizedTypeName.get(list, hoverboard);
330*53ff1f6bSSadaf Ebrahimi
331*53ff1f6bSSadaf EbrahimiMethodSpec beyond = MethodSpec.methodBuilder("beyond")
332*53ff1f6bSSadaf Ebrahimi    .returns(listOfHoverboards)
333*53ff1f6bSSadaf Ebrahimi    .addStatement("$T result = new $T<>()", listOfHoverboards, arrayList)
334*53ff1f6bSSadaf Ebrahimi    .addStatement("result.add(new $T())", hoverboard)
335*53ff1f6bSSadaf Ebrahimi    .addStatement("result.add(new $T())", hoverboard)
336*53ff1f6bSSadaf Ebrahimi    .addStatement("result.add(new $T())", hoverboard)
337*53ff1f6bSSadaf Ebrahimi    .addStatement("return result")
338*53ff1f6bSSadaf Ebrahimi    .build();
339*53ff1f6bSSadaf Ebrahimi```
340*53ff1f6bSSadaf Ebrahimi
341*53ff1f6bSSadaf EbrahimiJavaPoet will decompose each type and import its components where possible.
342*53ff1f6bSSadaf Ebrahimi
343*53ff1f6bSSadaf Ebrahimi```java
344*53ff1f6bSSadaf Ebrahimipackage com.example.helloworld;
345*53ff1f6bSSadaf Ebrahimi
346*53ff1f6bSSadaf Ebrahimiimport com.mattel.Hoverboard;
347*53ff1f6bSSadaf Ebrahimiimport java.util.ArrayList;
348*53ff1f6bSSadaf Ebrahimiimport java.util.List;
349*53ff1f6bSSadaf Ebrahimi
350*53ff1f6bSSadaf Ebrahimipublic final class HelloWorld {
351*53ff1f6bSSadaf Ebrahimi  List<Hoverboard> beyond() {
352*53ff1f6bSSadaf Ebrahimi    List<Hoverboard> result = new ArrayList<>();
353*53ff1f6bSSadaf Ebrahimi    result.add(new Hoverboard());
354*53ff1f6bSSadaf Ebrahimi    result.add(new Hoverboard());
355*53ff1f6bSSadaf Ebrahimi    result.add(new Hoverboard());
356*53ff1f6bSSadaf Ebrahimi    return result;
357*53ff1f6bSSadaf Ebrahimi  }
358*53ff1f6bSSadaf Ebrahimi}
359*53ff1f6bSSadaf Ebrahimi```
360*53ff1f6bSSadaf Ebrahimi
361*53ff1f6bSSadaf Ebrahimi#### Import static
362*53ff1f6bSSadaf Ebrahimi
363*53ff1f6bSSadaf EbrahimiJavaPoet supports `import static`. It does it via explicitly collecting type member names. Let's
364*53ff1f6bSSadaf Ebrahimienhance the previous example with some static sugar:
365*53ff1f6bSSadaf Ebrahimi
366*53ff1f6bSSadaf Ebrahimi```java
367*53ff1f6bSSadaf Ebrahimi...
368*53ff1f6bSSadaf EbrahimiClassName namedBoards = ClassName.get("com.mattel", "Hoverboard", "Boards");
369*53ff1f6bSSadaf Ebrahimi
370*53ff1f6bSSadaf EbrahimiMethodSpec beyond = MethodSpec.methodBuilder("beyond")
371*53ff1f6bSSadaf Ebrahimi    .returns(listOfHoverboards)
372*53ff1f6bSSadaf Ebrahimi    .addStatement("$T result = new $T<>()", listOfHoverboards, arrayList)
373*53ff1f6bSSadaf Ebrahimi    .addStatement("result.add($T.createNimbus(2000))", hoverboard)
374*53ff1f6bSSadaf Ebrahimi    .addStatement("result.add($T.createNimbus(\"2001\"))", hoverboard)
375*53ff1f6bSSadaf Ebrahimi    .addStatement("result.add($T.createNimbus($T.THUNDERBOLT))", hoverboard, namedBoards)
376*53ff1f6bSSadaf Ebrahimi    .addStatement("$T.sort(result)", Collections.class)
377*53ff1f6bSSadaf Ebrahimi    .addStatement("return result.isEmpty() ? $T.emptyList() : result", Collections.class)
378*53ff1f6bSSadaf Ebrahimi    .build();
379*53ff1f6bSSadaf Ebrahimi
380*53ff1f6bSSadaf EbrahimiTypeSpec hello = TypeSpec.classBuilder("HelloWorld")
381*53ff1f6bSSadaf Ebrahimi    .addMethod(beyond)
382*53ff1f6bSSadaf Ebrahimi    .build();
383*53ff1f6bSSadaf Ebrahimi
384*53ff1f6bSSadaf EbrahimiJavaFile.builder("com.example.helloworld", hello)
385*53ff1f6bSSadaf Ebrahimi    .addStaticImport(hoverboard, "createNimbus")
386*53ff1f6bSSadaf Ebrahimi    .addStaticImport(namedBoards, "*")
387*53ff1f6bSSadaf Ebrahimi    .addStaticImport(Collections.class, "*")
388*53ff1f6bSSadaf Ebrahimi    .build();
389*53ff1f6bSSadaf Ebrahimi```
390*53ff1f6bSSadaf Ebrahimi
391*53ff1f6bSSadaf EbrahimiJavaPoet will first add your `import static` block to the file as configured, match and mangle
392*53ff1f6bSSadaf Ebrahimiall calls accordingly and also import all other types as needed.
393*53ff1f6bSSadaf Ebrahimi
394*53ff1f6bSSadaf Ebrahimi```java
395*53ff1f6bSSadaf Ebrahimipackage com.example.helloworld;
396*53ff1f6bSSadaf Ebrahimi
397*53ff1f6bSSadaf Ebrahimiimport static com.mattel.Hoverboard.Boards.*;
398*53ff1f6bSSadaf Ebrahimiimport static com.mattel.Hoverboard.createNimbus;
399*53ff1f6bSSadaf Ebrahimiimport static java.util.Collections.*;
400*53ff1f6bSSadaf Ebrahimi
401*53ff1f6bSSadaf Ebrahimiimport com.mattel.Hoverboard;
402*53ff1f6bSSadaf Ebrahimiimport java.util.ArrayList;
403*53ff1f6bSSadaf Ebrahimiimport java.util.List;
404*53ff1f6bSSadaf Ebrahimi
405*53ff1f6bSSadaf Ebrahimiclass HelloWorld {
406*53ff1f6bSSadaf Ebrahimi  List<Hoverboard> beyond() {
407*53ff1f6bSSadaf Ebrahimi    List<Hoverboard> result = new ArrayList<>();
408*53ff1f6bSSadaf Ebrahimi    result.add(createNimbus(2000));
409*53ff1f6bSSadaf Ebrahimi    result.add(createNimbus("2001"));
410*53ff1f6bSSadaf Ebrahimi    result.add(createNimbus(THUNDERBOLT));
411*53ff1f6bSSadaf Ebrahimi    sort(result);
412*53ff1f6bSSadaf Ebrahimi    return result.isEmpty() ? emptyList() : result;
413*53ff1f6bSSadaf Ebrahimi  }
414*53ff1f6bSSadaf Ebrahimi}
415*53ff1f6bSSadaf Ebrahimi```
416*53ff1f6bSSadaf Ebrahimi
417*53ff1f6bSSadaf Ebrahimi### $N for Names
418*53ff1f6bSSadaf Ebrahimi
419*53ff1f6bSSadaf EbrahimiGenerated code is often self-referential. Use **`$N`** to refer to another generated declaration by
420*53ff1f6bSSadaf Ebrahimiits name. Here's a method that calls another:
421*53ff1f6bSSadaf Ebrahimi
422*53ff1f6bSSadaf Ebrahimi```java
423*53ff1f6bSSadaf Ebrahimipublic String byteToHex(int b) {
424*53ff1f6bSSadaf Ebrahimi  char[] result = new char[2];
425*53ff1f6bSSadaf Ebrahimi  result[0] = hexDigit((b >>> 4) & 0xf);
426*53ff1f6bSSadaf Ebrahimi  result[1] = hexDigit(b & 0xf);
427*53ff1f6bSSadaf Ebrahimi  return new String(result);
428*53ff1f6bSSadaf Ebrahimi}
429*53ff1f6bSSadaf Ebrahimi
430*53ff1f6bSSadaf Ebrahimipublic char hexDigit(int i) {
431*53ff1f6bSSadaf Ebrahimi  return (char) (i < 10 ? i + '0' : i - 10 + 'a');
432*53ff1f6bSSadaf Ebrahimi}
433*53ff1f6bSSadaf Ebrahimi```
434*53ff1f6bSSadaf Ebrahimi
435*53ff1f6bSSadaf EbrahimiWhen generating the code above, we pass the `hexDigit()` method as an argument to the `byteToHex()`
436*53ff1f6bSSadaf Ebrahimimethod using `$N`:
437*53ff1f6bSSadaf Ebrahimi
438*53ff1f6bSSadaf Ebrahimi```java
439*53ff1f6bSSadaf EbrahimiMethodSpec hexDigit = MethodSpec.methodBuilder("hexDigit")
440*53ff1f6bSSadaf Ebrahimi    .addParameter(int.class, "i")
441*53ff1f6bSSadaf Ebrahimi    .returns(char.class)
442*53ff1f6bSSadaf Ebrahimi    .addStatement("return (char) (i < 10 ? i + '0' : i - 10 + 'a')")
443*53ff1f6bSSadaf Ebrahimi    .build();
444*53ff1f6bSSadaf Ebrahimi
445*53ff1f6bSSadaf EbrahimiMethodSpec byteToHex = MethodSpec.methodBuilder("byteToHex")
446*53ff1f6bSSadaf Ebrahimi    .addParameter(int.class, "b")
447*53ff1f6bSSadaf Ebrahimi    .returns(String.class)
448*53ff1f6bSSadaf Ebrahimi    .addStatement("char[] result = new char[2]")
449*53ff1f6bSSadaf Ebrahimi    .addStatement("result[0] = $N((b >>> 4) & 0xf)", hexDigit)
450*53ff1f6bSSadaf Ebrahimi    .addStatement("result[1] = $N(b & 0xf)", hexDigit)
451*53ff1f6bSSadaf Ebrahimi    .addStatement("return new String(result)")
452*53ff1f6bSSadaf Ebrahimi    .build();
453*53ff1f6bSSadaf Ebrahimi```
454*53ff1f6bSSadaf Ebrahimi
455*53ff1f6bSSadaf Ebrahimi### Code block format strings
456*53ff1f6bSSadaf Ebrahimi
457*53ff1f6bSSadaf EbrahimiCode blocks may specify the values for their placeholders in a few ways. Only one style may be used
458*53ff1f6bSSadaf Ebrahimifor each operation on a code block.
459*53ff1f6bSSadaf Ebrahimi
460*53ff1f6bSSadaf Ebrahimi#### Relative Arguments
461*53ff1f6bSSadaf Ebrahimi
462*53ff1f6bSSadaf EbrahimiPass an argument value for each placeholder in the format string to `CodeBlock.add()`. In each
463*53ff1f6bSSadaf Ebrahimiexample, we generate code to say "I ate 3 tacos"
464*53ff1f6bSSadaf Ebrahimi
465*53ff1f6bSSadaf Ebrahimi```java
466*53ff1f6bSSadaf EbrahimiCodeBlock.builder().add("I ate $L $L", 3, "tacos")
467*53ff1f6bSSadaf Ebrahimi```
468*53ff1f6bSSadaf Ebrahimi
469*53ff1f6bSSadaf Ebrahimi#### Positional Arguments
470*53ff1f6bSSadaf Ebrahimi
471*53ff1f6bSSadaf EbrahimiPlace an integer index (1-based) before the placeholder in the format string to specify which
472*53ff1f6bSSadaf Ebrahimi argument to use.
473*53ff1f6bSSadaf Ebrahimi
474*53ff1f6bSSadaf Ebrahimi```java
475*53ff1f6bSSadaf EbrahimiCodeBlock.builder().add("I ate $2L $1L", "tacos", 3)
476*53ff1f6bSSadaf Ebrahimi```
477*53ff1f6bSSadaf Ebrahimi
478*53ff1f6bSSadaf Ebrahimi#### Named Arguments
479*53ff1f6bSSadaf Ebrahimi
480*53ff1f6bSSadaf EbrahimiUse the syntax `$argumentName:X` where `X` is the format character and call `CodeBlock.addNamed()`
481*53ff1f6bSSadaf Ebrahimiwith a map containing all argument keys in the format string. Argument names use characters in
482*53ff1f6bSSadaf Ebrahimi`a-z`, `A-Z`, `0-9`, and `_`, and must start with a lowercase character.
483*53ff1f6bSSadaf Ebrahimi
484*53ff1f6bSSadaf Ebrahimi```java
485*53ff1f6bSSadaf EbrahimiMap<String, Object> map = new LinkedHashMap<>();
486*53ff1f6bSSadaf Ebrahimimap.put("food", "tacos");
487*53ff1f6bSSadaf Ebrahimimap.put("count", 3);
488*53ff1f6bSSadaf EbrahimiCodeBlock.builder().addNamed("I ate $count:L $food:L", map)
489*53ff1f6bSSadaf Ebrahimi```
490*53ff1f6bSSadaf Ebrahimi
491*53ff1f6bSSadaf Ebrahimi### Methods
492*53ff1f6bSSadaf Ebrahimi
493*53ff1f6bSSadaf EbrahimiAll of the above methods have a code body. Use `Modifiers.ABSTRACT` to get a method without any
494*53ff1f6bSSadaf Ebrahimibody. This is only legal if the enclosing class is either abstract or an interface.
495*53ff1f6bSSadaf Ebrahimi
496*53ff1f6bSSadaf Ebrahimi```java
497*53ff1f6bSSadaf EbrahimiMethodSpec flux = MethodSpec.methodBuilder("flux")
498*53ff1f6bSSadaf Ebrahimi    .addModifiers(Modifier.ABSTRACT, Modifier.PROTECTED)
499*53ff1f6bSSadaf Ebrahimi    .build();
500*53ff1f6bSSadaf Ebrahimi
501*53ff1f6bSSadaf EbrahimiTypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
502*53ff1f6bSSadaf Ebrahimi    .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
503*53ff1f6bSSadaf Ebrahimi    .addMethod(flux)
504*53ff1f6bSSadaf Ebrahimi    .build();
505*53ff1f6bSSadaf Ebrahimi```
506*53ff1f6bSSadaf Ebrahimi
507*53ff1f6bSSadaf EbrahimiWhich generates this:
508*53ff1f6bSSadaf Ebrahimi
509*53ff1f6bSSadaf Ebrahimi```java
510*53ff1f6bSSadaf Ebrahimipublic abstract class HelloWorld {
511*53ff1f6bSSadaf Ebrahimi  protected abstract void flux();
512*53ff1f6bSSadaf Ebrahimi}
513*53ff1f6bSSadaf Ebrahimi```
514*53ff1f6bSSadaf Ebrahimi
515*53ff1f6bSSadaf EbrahimiThe other modifiers work where permitted. Note that when specifying modifiers, JavaPoet uses
516*53ff1f6bSSadaf Ebrahimi[`javax.lang.model.element.Modifier`][modifier], a class that is not available on Android. This
517*53ff1f6bSSadaf Ebrahimilimitation applies to code-generating-code only; the output code runs everywhere: JVMs, Android,
518*53ff1f6bSSadaf Ebrahimiand GWT.
519*53ff1f6bSSadaf Ebrahimi
520*53ff1f6bSSadaf EbrahimiMethods also have parameters, exceptions, varargs, Javadoc, annotations, type variables, and a
521*53ff1f6bSSadaf Ebrahimireturn type. All of these are configured with `MethodSpec.Builder`.
522*53ff1f6bSSadaf Ebrahimi
523*53ff1f6bSSadaf Ebrahimi### Constructors
524*53ff1f6bSSadaf Ebrahimi
525*53ff1f6bSSadaf Ebrahimi`MethodSpec` is a slight misnomer; it can also be used for constructors:
526*53ff1f6bSSadaf Ebrahimi
527*53ff1f6bSSadaf Ebrahimi```java
528*53ff1f6bSSadaf EbrahimiMethodSpec flux = MethodSpec.constructorBuilder()
529*53ff1f6bSSadaf Ebrahimi    .addModifiers(Modifier.PUBLIC)
530*53ff1f6bSSadaf Ebrahimi    .addParameter(String.class, "greeting")
531*53ff1f6bSSadaf Ebrahimi    .addStatement("this.$N = $N", "greeting", "greeting")
532*53ff1f6bSSadaf Ebrahimi    .build();
533*53ff1f6bSSadaf Ebrahimi
534*53ff1f6bSSadaf EbrahimiTypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
535*53ff1f6bSSadaf Ebrahimi    .addModifiers(Modifier.PUBLIC)
536*53ff1f6bSSadaf Ebrahimi    .addField(String.class, "greeting", Modifier.PRIVATE, Modifier.FINAL)
537*53ff1f6bSSadaf Ebrahimi    .addMethod(flux)
538*53ff1f6bSSadaf Ebrahimi    .build();
539*53ff1f6bSSadaf Ebrahimi```
540*53ff1f6bSSadaf Ebrahimi
541*53ff1f6bSSadaf EbrahimiWhich generates this:
542*53ff1f6bSSadaf Ebrahimi
543*53ff1f6bSSadaf Ebrahimi```java
544*53ff1f6bSSadaf Ebrahimipublic class HelloWorld {
545*53ff1f6bSSadaf Ebrahimi  private final String greeting;
546*53ff1f6bSSadaf Ebrahimi
547*53ff1f6bSSadaf Ebrahimi  public HelloWorld(String greeting) {
548*53ff1f6bSSadaf Ebrahimi    this.greeting = greeting;
549*53ff1f6bSSadaf Ebrahimi  }
550*53ff1f6bSSadaf Ebrahimi}
551*53ff1f6bSSadaf Ebrahimi```
552*53ff1f6bSSadaf Ebrahimi
553*53ff1f6bSSadaf EbrahimiFor the most part, constructors work just like methods. When emitting code, JavaPoet will place
554*53ff1f6bSSadaf Ebrahimiconstructors before methods in the output file.
555*53ff1f6bSSadaf Ebrahimi
556*53ff1f6bSSadaf Ebrahimi### Parameters
557*53ff1f6bSSadaf Ebrahimi
558*53ff1f6bSSadaf EbrahimiDeclare parameters on methods and constructors with either `ParameterSpec.builder()` or
559*53ff1f6bSSadaf Ebrahimi`MethodSpec`'s convenient `addParameter()` API:
560*53ff1f6bSSadaf Ebrahimi
561*53ff1f6bSSadaf Ebrahimi```java
562*53ff1f6bSSadaf EbrahimiParameterSpec android = ParameterSpec.builder(String.class, "android")
563*53ff1f6bSSadaf Ebrahimi    .addModifiers(Modifier.FINAL)
564*53ff1f6bSSadaf Ebrahimi    .build();
565*53ff1f6bSSadaf Ebrahimi
566*53ff1f6bSSadaf EbrahimiMethodSpec welcomeOverlords = MethodSpec.methodBuilder("welcomeOverlords")
567*53ff1f6bSSadaf Ebrahimi    .addParameter(android)
568*53ff1f6bSSadaf Ebrahimi    .addParameter(String.class, "robot", Modifier.FINAL)
569*53ff1f6bSSadaf Ebrahimi    .build();
570*53ff1f6bSSadaf Ebrahimi```
571*53ff1f6bSSadaf Ebrahimi
572*53ff1f6bSSadaf EbrahimiThough the code above to generate `android` and `robot` parameters is different, the output is the
573*53ff1f6bSSadaf Ebrahimisame:
574*53ff1f6bSSadaf Ebrahimi
575*53ff1f6bSSadaf Ebrahimi```java
576*53ff1f6bSSadaf Ebrahimivoid welcomeOverlords(final String android, final String robot) {
577*53ff1f6bSSadaf Ebrahimi}
578*53ff1f6bSSadaf Ebrahimi```
579*53ff1f6bSSadaf Ebrahimi
580*53ff1f6bSSadaf EbrahimiThe extended `Builder` form is necessary when the parameter has annotations (such as `@Nullable`).
581*53ff1f6bSSadaf Ebrahimi
582*53ff1f6bSSadaf Ebrahimi### Fields
583*53ff1f6bSSadaf Ebrahimi
584*53ff1f6bSSadaf EbrahimiLike parameters, fields can be created either with builders or by using convenient helper methods:
585*53ff1f6bSSadaf Ebrahimi
586*53ff1f6bSSadaf Ebrahimi```java
587*53ff1f6bSSadaf EbrahimiFieldSpec android = FieldSpec.builder(String.class, "android")
588*53ff1f6bSSadaf Ebrahimi    .addModifiers(Modifier.PRIVATE, Modifier.FINAL)
589*53ff1f6bSSadaf Ebrahimi    .build();
590*53ff1f6bSSadaf Ebrahimi
591*53ff1f6bSSadaf EbrahimiTypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
592*53ff1f6bSSadaf Ebrahimi    .addModifiers(Modifier.PUBLIC)
593*53ff1f6bSSadaf Ebrahimi    .addField(android)
594*53ff1f6bSSadaf Ebrahimi    .addField(String.class, "robot", Modifier.PRIVATE, Modifier.FINAL)
595*53ff1f6bSSadaf Ebrahimi    .build();
596*53ff1f6bSSadaf Ebrahimi```
597*53ff1f6bSSadaf Ebrahimi
598*53ff1f6bSSadaf EbrahimiWhich generates:
599*53ff1f6bSSadaf Ebrahimi
600*53ff1f6bSSadaf Ebrahimi```java
601*53ff1f6bSSadaf Ebrahimipublic class HelloWorld {
602*53ff1f6bSSadaf Ebrahimi  private final String android;
603*53ff1f6bSSadaf Ebrahimi
604*53ff1f6bSSadaf Ebrahimi  private final String robot;
605*53ff1f6bSSadaf Ebrahimi}
606*53ff1f6bSSadaf Ebrahimi```
607*53ff1f6bSSadaf Ebrahimi
608*53ff1f6bSSadaf EbrahimiThe extended `Builder` form is necessary when a field has Javadoc, annotations, or a field
609*53ff1f6bSSadaf Ebrahimiinitializer. Field initializers use the same [`String.format()`][formatter]-like syntax as the code
610*53ff1f6bSSadaf Ebrahimiblocks above:
611*53ff1f6bSSadaf Ebrahimi
612*53ff1f6bSSadaf Ebrahimi```java
613*53ff1f6bSSadaf EbrahimiFieldSpec android = FieldSpec.builder(String.class, "android")
614*53ff1f6bSSadaf Ebrahimi    .addModifiers(Modifier.PRIVATE, Modifier.FINAL)
615*53ff1f6bSSadaf Ebrahimi    .initializer("$S + $L", "Lollipop v.", 5.0d)
616*53ff1f6bSSadaf Ebrahimi    .build();
617*53ff1f6bSSadaf Ebrahimi```
618*53ff1f6bSSadaf Ebrahimi
619*53ff1f6bSSadaf EbrahimiWhich generates:
620*53ff1f6bSSadaf Ebrahimi
621*53ff1f6bSSadaf Ebrahimi```java
622*53ff1f6bSSadaf Ebrahimiprivate final String android = "Lollipop v." + 5.0;
623*53ff1f6bSSadaf Ebrahimi```
624*53ff1f6bSSadaf Ebrahimi
625*53ff1f6bSSadaf Ebrahimi### Interfaces
626*53ff1f6bSSadaf Ebrahimi
627*53ff1f6bSSadaf EbrahimiJavaPoet has no trouble with interfaces. Note that interface methods must always be `PUBLIC
628*53ff1f6bSSadaf EbrahimiABSTRACT` and interface fields must always be `PUBLIC STATIC FINAL`. These modifiers are necessary
629*53ff1f6bSSadaf Ebrahimiwhen defining the interface:
630*53ff1f6bSSadaf Ebrahimi
631*53ff1f6bSSadaf Ebrahimi```java
632*53ff1f6bSSadaf EbrahimiTypeSpec helloWorld = TypeSpec.interfaceBuilder("HelloWorld")
633*53ff1f6bSSadaf Ebrahimi    .addModifiers(Modifier.PUBLIC)
634*53ff1f6bSSadaf Ebrahimi    .addField(FieldSpec.builder(String.class, "ONLY_THING_THAT_IS_CONSTANT")
635*53ff1f6bSSadaf Ebrahimi        .addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
636*53ff1f6bSSadaf Ebrahimi        .initializer("$S", "change")
637*53ff1f6bSSadaf Ebrahimi        .build())
638*53ff1f6bSSadaf Ebrahimi    .addMethod(MethodSpec.methodBuilder("beep")
639*53ff1f6bSSadaf Ebrahimi        .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
640*53ff1f6bSSadaf Ebrahimi        .build())
641*53ff1f6bSSadaf Ebrahimi    .build();
642*53ff1f6bSSadaf Ebrahimi```
643*53ff1f6bSSadaf Ebrahimi
644*53ff1f6bSSadaf EbrahimiBut these modifiers are omitted when the code is generated. These are the defaults so we don't need
645*53ff1f6bSSadaf Ebrahimito include them for `javac`'s benefit!
646*53ff1f6bSSadaf Ebrahimi
647*53ff1f6bSSadaf Ebrahimi```java
648*53ff1f6bSSadaf Ebrahimipublic interface HelloWorld {
649*53ff1f6bSSadaf Ebrahimi  String ONLY_THING_THAT_IS_CONSTANT = "change";
650*53ff1f6bSSadaf Ebrahimi
651*53ff1f6bSSadaf Ebrahimi  void beep();
652*53ff1f6bSSadaf Ebrahimi}
653*53ff1f6bSSadaf Ebrahimi```
654*53ff1f6bSSadaf Ebrahimi
655*53ff1f6bSSadaf Ebrahimi### Enums
656*53ff1f6bSSadaf Ebrahimi
657*53ff1f6bSSadaf EbrahimiUse `enumBuilder` to create the enum type, and `addEnumConstant()` for each value:
658*53ff1f6bSSadaf Ebrahimi
659*53ff1f6bSSadaf Ebrahimi```java
660*53ff1f6bSSadaf EbrahimiTypeSpec helloWorld = TypeSpec.enumBuilder("Roshambo")
661*53ff1f6bSSadaf Ebrahimi    .addModifiers(Modifier.PUBLIC)
662*53ff1f6bSSadaf Ebrahimi    .addEnumConstant("ROCK")
663*53ff1f6bSSadaf Ebrahimi    .addEnumConstant("SCISSORS")
664*53ff1f6bSSadaf Ebrahimi    .addEnumConstant("PAPER")
665*53ff1f6bSSadaf Ebrahimi    .build();
666*53ff1f6bSSadaf Ebrahimi```
667*53ff1f6bSSadaf Ebrahimi
668*53ff1f6bSSadaf EbrahimiTo generate this:
669*53ff1f6bSSadaf Ebrahimi
670*53ff1f6bSSadaf Ebrahimi```java
671*53ff1f6bSSadaf Ebrahimipublic enum Roshambo {
672*53ff1f6bSSadaf Ebrahimi  ROCK,
673*53ff1f6bSSadaf Ebrahimi
674*53ff1f6bSSadaf Ebrahimi  SCISSORS,
675*53ff1f6bSSadaf Ebrahimi
676*53ff1f6bSSadaf Ebrahimi  PAPER
677*53ff1f6bSSadaf Ebrahimi}
678*53ff1f6bSSadaf Ebrahimi```
679*53ff1f6bSSadaf Ebrahimi
680*53ff1f6bSSadaf EbrahimiFancy enums are supported, where the enum values override methods or call a superclass constructor.
681*53ff1f6bSSadaf EbrahimiHere's a comprehensive example:
682*53ff1f6bSSadaf Ebrahimi
683*53ff1f6bSSadaf Ebrahimi```java
684*53ff1f6bSSadaf EbrahimiTypeSpec helloWorld = TypeSpec.enumBuilder("Roshambo")
685*53ff1f6bSSadaf Ebrahimi    .addModifiers(Modifier.PUBLIC)
686*53ff1f6bSSadaf Ebrahimi    .addEnumConstant("ROCK", TypeSpec.anonymousClassBuilder("$S", "fist")
687*53ff1f6bSSadaf Ebrahimi        .addMethod(MethodSpec.methodBuilder("toString")
688*53ff1f6bSSadaf Ebrahimi            .addAnnotation(Override.class)
689*53ff1f6bSSadaf Ebrahimi            .addModifiers(Modifier.PUBLIC)
690*53ff1f6bSSadaf Ebrahimi            .addStatement("return $S", "avalanche!")
691*53ff1f6bSSadaf Ebrahimi            .returns(String.class)
692*53ff1f6bSSadaf Ebrahimi            .build())
693*53ff1f6bSSadaf Ebrahimi        .build())
694*53ff1f6bSSadaf Ebrahimi    .addEnumConstant("SCISSORS", TypeSpec.anonymousClassBuilder("$S", "peace")
695*53ff1f6bSSadaf Ebrahimi        .build())
696*53ff1f6bSSadaf Ebrahimi    .addEnumConstant("PAPER", TypeSpec.anonymousClassBuilder("$S", "flat")
697*53ff1f6bSSadaf Ebrahimi        .build())
698*53ff1f6bSSadaf Ebrahimi    .addField(String.class, "handsign", Modifier.PRIVATE, Modifier.FINAL)
699*53ff1f6bSSadaf Ebrahimi    .addMethod(MethodSpec.constructorBuilder()
700*53ff1f6bSSadaf Ebrahimi        .addParameter(String.class, "handsign")
701*53ff1f6bSSadaf Ebrahimi        .addStatement("this.$N = $N", "handsign", "handsign")
702*53ff1f6bSSadaf Ebrahimi        .build())
703*53ff1f6bSSadaf Ebrahimi    .build();
704*53ff1f6bSSadaf Ebrahimi```
705*53ff1f6bSSadaf Ebrahimi
706*53ff1f6bSSadaf EbrahimiWhich generates this:
707*53ff1f6bSSadaf Ebrahimi
708*53ff1f6bSSadaf Ebrahimi```java
709*53ff1f6bSSadaf Ebrahimipublic enum Roshambo {
710*53ff1f6bSSadaf Ebrahimi  ROCK("fist") {
711*53ff1f6bSSadaf Ebrahimi    @Override
712*53ff1f6bSSadaf Ebrahimi    public String toString() {
713*53ff1f6bSSadaf Ebrahimi      return "avalanche!";
714*53ff1f6bSSadaf Ebrahimi    }
715*53ff1f6bSSadaf Ebrahimi  },
716*53ff1f6bSSadaf Ebrahimi
717*53ff1f6bSSadaf Ebrahimi  SCISSORS("peace"),
718*53ff1f6bSSadaf Ebrahimi
719*53ff1f6bSSadaf Ebrahimi  PAPER("flat");
720*53ff1f6bSSadaf Ebrahimi
721*53ff1f6bSSadaf Ebrahimi  private final String handsign;
722*53ff1f6bSSadaf Ebrahimi
723*53ff1f6bSSadaf Ebrahimi  Roshambo(String handsign) {
724*53ff1f6bSSadaf Ebrahimi    this.handsign = handsign;
725*53ff1f6bSSadaf Ebrahimi  }
726*53ff1f6bSSadaf Ebrahimi}
727*53ff1f6bSSadaf Ebrahimi```
728*53ff1f6bSSadaf Ebrahimi
729*53ff1f6bSSadaf Ebrahimi### Anonymous Inner Classes
730*53ff1f6bSSadaf Ebrahimi
731*53ff1f6bSSadaf EbrahimiIn the enum code, we used `TypeSpec.anonymousInnerClass()`. Anonymous inner classes can also be used in
732*53ff1f6bSSadaf Ebrahimicode blocks. They are values that can be referenced with `$L`:
733*53ff1f6bSSadaf Ebrahimi
734*53ff1f6bSSadaf Ebrahimi```java
735*53ff1f6bSSadaf EbrahimiTypeSpec comparator = TypeSpec.anonymousClassBuilder("")
736*53ff1f6bSSadaf Ebrahimi    .addSuperinterface(ParameterizedTypeName.get(Comparator.class, String.class))
737*53ff1f6bSSadaf Ebrahimi    .addMethod(MethodSpec.methodBuilder("compare")
738*53ff1f6bSSadaf Ebrahimi        .addAnnotation(Override.class)
739*53ff1f6bSSadaf Ebrahimi        .addModifiers(Modifier.PUBLIC)
740*53ff1f6bSSadaf Ebrahimi        .addParameter(String.class, "a")
741*53ff1f6bSSadaf Ebrahimi        .addParameter(String.class, "b")
742*53ff1f6bSSadaf Ebrahimi        .returns(int.class)
743*53ff1f6bSSadaf Ebrahimi        .addStatement("return $N.length() - $N.length()", "a", "b")
744*53ff1f6bSSadaf Ebrahimi        .build())
745*53ff1f6bSSadaf Ebrahimi    .build();
746*53ff1f6bSSadaf Ebrahimi
747*53ff1f6bSSadaf EbrahimiTypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
748*53ff1f6bSSadaf Ebrahimi    .addMethod(MethodSpec.methodBuilder("sortByLength")
749*53ff1f6bSSadaf Ebrahimi        .addParameter(ParameterizedTypeName.get(List.class, String.class), "strings")
750*53ff1f6bSSadaf Ebrahimi        .addStatement("$T.sort($N, $L)", Collections.class, "strings", comparator)
751*53ff1f6bSSadaf Ebrahimi        .build())
752*53ff1f6bSSadaf Ebrahimi    .build();
753*53ff1f6bSSadaf Ebrahimi```
754*53ff1f6bSSadaf Ebrahimi
755*53ff1f6bSSadaf EbrahimiThis generates a method that contains a class that contains a method:
756*53ff1f6bSSadaf Ebrahimi
757*53ff1f6bSSadaf Ebrahimi```java
758*53ff1f6bSSadaf Ebrahimivoid sortByLength(List<String> strings) {
759*53ff1f6bSSadaf Ebrahimi  Collections.sort(strings, new Comparator<String>() {
760*53ff1f6bSSadaf Ebrahimi    @Override
761*53ff1f6bSSadaf Ebrahimi    public int compare(String a, String b) {
762*53ff1f6bSSadaf Ebrahimi      return a.length() - b.length();
763*53ff1f6bSSadaf Ebrahimi    }
764*53ff1f6bSSadaf Ebrahimi  });
765*53ff1f6bSSadaf Ebrahimi}
766*53ff1f6bSSadaf Ebrahimi```
767*53ff1f6bSSadaf Ebrahimi
768*53ff1f6bSSadaf EbrahimiOne particularly tricky part of defining anonymous inner classes is the arguments to the superclass
769*53ff1f6bSSadaf Ebrahimiconstructor. In the above code we're passing the empty string for no arguments:
770*53ff1f6bSSadaf Ebrahimi`TypeSpec.anonymousClassBuilder("")`. To pass different parameters use JavaPoet's code block
771*53ff1f6bSSadaf Ebrahimisyntax with commas to separate arguments.
772*53ff1f6bSSadaf Ebrahimi
773*53ff1f6bSSadaf Ebrahimi
774*53ff1f6bSSadaf Ebrahimi### Annotations
775*53ff1f6bSSadaf Ebrahimi
776*53ff1f6bSSadaf EbrahimiSimple annotations are easy:
777*53ff1f6bSSadaf Ebrahimi
778*53ff1f6bSSadaf Ebrahimi```java
779*53ff1f6bSSadaf EbrahimiMethodSpec toString = MethodSpec.methodBuilder("toString")
780*53ff1f6bSSadaf Ebrahimi    .addAnnotation(Override.class)
781*53ff1f6bSSadaf Ebrahimi    .returns(String.class)
782*53ff1f6bSSadaf Ebrahimi    .addModifiers(Modifier.PUBLIC)
783*53ff1f6bSSadaf Ebrahimi    .addStatement("return $S", "Hoverboard")
784*53ff1f6bSSadaf Ebrahimi    .build();
785*53ff1f6bSSadaf Ebrahimi```
786*53ff1f6bSSadaf Ebrahimi
787*53ff1f6bSSadaf EbrahimiWhich generates this method with an `@Override` annotation:
788*53ff1f6bSSadaf Ebrahimi
789*53ff1f6bSSadaf Ebrahimi```java
790*53ff1f6bSSadaf Ebrahimi  @Override
791*53ff1f6bSSadaf Ebrahimi  public String toString() {
792*53ff1f6bSSadaf Ebrahimi    return "Hoverboard";
793*53ff1f6bSSadaf Ebrahimi  }
794*53ff1f6bSSadaf Ebrahimi```
795*53ff1f6bSSadaf Ebrahimi
796*53ff1f6bSSadaf EbrahimiUse `AnnotationSpec.builder()` to set properties on annotations:
797*53ff1f6bSSadaf Ebrahimi
798*53ff1f6bSSadaf Ebrahimi```java
799*53ff1f6bSSadaf EbrahimiMethodSpec logRecord = MethodSpec.methodBuilder("recordEvent")
800*53ff1f6bSSadaf Ebrahimi    .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
801*53ff1f6bSSadaf Ebrahimi    .addAnnotation(AnnotationSpec.builder(Headers.class)
802*53ff1f6bSSadaf Ebrahimi        .addMember("accept", "$S", "application/json; charset=utf-8")
803*53ff1f6bSSadaf Ebrahimi        .addMember("userAgent", "$S", "Square Cash")
804*53ff1f6bSSadaf Ebrahimi        .build())
805*53ff1f6bSSadaf Ebrahimi    .addParameter(LogRecord.class, "logRecord")
806*53ff1f6bSSadaf Ebrahimi    .returns(LogReceipt.class)
807*53ff1f6bSSadaf Ebrahimi    .build();
808*53ff1f6bSSadaf Ebrahimi```
809*53ff1f6bSSadaf Ebrahimi
810*53ff1f6bSSadaf EbrahimiWhich generates this annotation with `accept` and `userAgent` properties:
811*53ff1f6bSSadaf Ebrahimi
812*53ff1f6bSSadaf Ebrahimi```java
813*53ff1f6bSSadaf Ebrahimi@Headers(
814*53ff1f6bSSadaf Ebrahimi    accept = "application/json; charset=utf-8",
815*53ff1f6bSSadaf Ebrahimi    userAgent = "Square Cash"
816*53ff1f6bSSadaf Ebrahimi)
817*53ff1f6bSSadaf EbrahimiLogReceipt recordEvent(LogRecord logRecord);
818*53ff1f6bSSadaf Ebrahimi```
819*53ff1f6bSSadaf Ebrahimi
820*53ff1f6bSSadaf EbrahimiWhen you get fancy, annotation values can be annotations themselves. Use `$L` for embedded
821*53ff1f6bSSadaf Ebrahimiannotations:
822*53ff1f6bSSadaf Ebrahimi
823*53ff1f6bSSadaf Ebrahimi```java
824*53ff1f6bSSadaf EbrahimiMethodSpec logRecord = MethodSpec.methodBuilder("recordEvent")
825*53ff1f6bSSadaf Ebrahimi    .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
826*53ff1f6bSSadaf Ebrahimi    .addAnnotation(AnnotationSpec.builder(HeaderList.class)
827*53ff1f6bSSadaf Ebrahimi        .addMember("value", "$L", AnnotationSpec.builder(Header.class)
828*53ff1f6bSSadaf Ebrahimi            .addMember("name", "$S", "Accept")
829*53ff1f6bSSadaf Ebrahimi            .addMember("value", "$S", "application/json; charset=utf-8")
830*53ff1f6bSSadaf Ebrahimi            .build())
831*53ff1f6bSSadaf Ebrahimi        .addMember("value", "$L", AnnotationSpec.builder(Header.class)
832*53ff1f6bSSadaf Ebrahimi            .addMember("name", "$S", "User-Agent")
833*53ff1f6bSSadaf Ebrahimi            .addMember("value", "$S", "Square Cash")
834*53ff1f6bSSadaf Ebrahimi            .build())
835*53ff1f6bSSadaf Ebrahimi        .build())
836*53ff1f6bSSadaf Ebrahimi    .addParameter(LogRecord.class, "logRecord")
837*53ff1f6bSSadaf Ebrahimi    .returns(LogReceipt.class)
838*53ff1f6bSSadaf Ebrahimi    .build();
839*53ff1f6bSSadaf Ebrahimi```
840*53ff1f6bSSadaf Ebrahimi
841*53ff1f6bSSadaf EbrahimiWhich generates this:
842*53ff1f6bSSadaf Ebrahimi
843*53ff1f6bSSadaf Ebrahimi```java
844*53ff1f6bSSadaf Ebrahimi@HeaderList({
845*53ff1f6bSSadaf Ebrahimi    @Header(name = "Accept", value = "application/json; charset=utf-8"),
846*53ff1f6bSSadaf Ebrahimi    @Header(name = "User-Agent", value = "Square Cash")
847*53ff1f6bSSadaf Ebrahimi})
848*53ff1f6bSSadaf EbrahimiLogReceipt recordEvent(LogRecord logRecord);
849*53ff1f6bSSadaf Ebrahimi```
850*53ff1f6bSSadaf Ebrahimi
851*53ff1f6bSSadaf EbrahimiNote that you can call `addMember()` multiple times with the same property name to populate a list
852*53ff1f6bSSadaf Ebrahimiof values for that property.
853*53ff1f6bSSadaf Ebrahimi
854*53ff1f6bSSadaf Ebrahimi### Javadoc
855*53ff1f6bSSadaf Ebrahimi
856*53ff1f6bSSadaf EbrahimiFields, methods and types can be documented with Javadoc:
857*53ff1f6bSSadaf Ebrahimi
858*53ff1f6bSSadaf Ebrahimi```java
859*53ff1f6bSSadaf EbrahimiMethodSpec dismiss = MethodSpec.methodBuilder("dismiss")
860*53ff1f6bSSadaf Ebrahimi    .addJavadoc("Hides {@code message} from the caller's history. Other\n"
861*53ff1f6bSSadaf Ebrahimi        + "participants in the conversation will continue to see the\n"
862*53ff1f6bSSadaf Ebrahimi        + "message in their own history unless they also delete it.\n")
863*53ff1f6bSSadaf Ebrahimi    .addJavadoc("\n")
864*53ff1f6bSSadaf Ebrahimi    .addJavadoc("<p>Use {@link #delete($T)} to delete the entire\n"
865*53ff1f6bSSadaf Ebrahimi        + "conversation for all participants.\n", Conversation.class)
866*53ff1f6bSSadaf Ebrahimi    .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
867*53ff1f6bSSadaf Ebrahimi    .addParameter(Message.class, "message")
868*53ff1f6bSSadaf Ebrahimi    .build();
869*53ff1f6bSSadaf Ebrahimi```
870*53ff1f6bSSadaf Ebrahimi
871*53ff1f6bSSadaf EbrahimiWhich generates this:
872*53ff1f6bSSadaf Ebrahimi
873*53ff1f6bSSadaf Ebrahimi```java
874*53ff1f6bSSadaf Ebrahimi  /**
875*53ff1f6bSSadaf Ebrahimi   * Hides {@code message} from the caller's history. Other
876*53ff1f6bSSadaf Ebrahimi   * participants in the conversation will continue to see the
877*53ff1f6bSSadaf Ebrahimi   * message in their own history unless they also delete it.
878*53ff1f6bSSadaf Ebrahimi   *
879*53ff1f6bSSadaf Ebrahimi   * <p>Use {@link #delete(Conversation)} to delete the entire
880*53ff1f6bSSadaf Ebrahimi   * conversation for all participants.
881*53ff1f6bSSadaf Ebrahimi   */
882*53ff1f6bSSadaf Ebrahimi  void dismiss(Message message);
883*53ff1f6bSSadaf Ebrahimi```
884*53ff1f6bSSadaf Ebrahimi
885*53ff1f6bSSadaf EbrahimiUse `$T` when referencing types in Javadoc to get automatic imports.
886*53ff1f6bSSadaf Ebrahimi
887*53ff1f6bSSadaf EbrahimiDownload
888*53ff1f6bSSadaf Ebrahimi--------
889*53ff1f6bSSadaf Ebrahimi
890*53ff1f6bSSadaf EbrahimiDownload [the latest .jar][dl] or depend via Maven:
891*53ff1f6bSSadaf Ebrahimi```xml
892*53ff1f6bSSadaf Ebrahimi<dependency>
893*53ff1f6bSSadaf Ebrahimi  <groupId>com.squareup</groupId>
894*53ff1f6bSSadaf Ebrahimi  <artifactId>javapoet</artifactId>
895*53ff1f6bSSadaf Ebrahimi  <version>1.12.1</version>
896*53ff1f6bSSadaf Ebrahimi</dependency>
897*53ff1f6bSSadaf Ebrahimi```
898*53ff1f6bSSadaf Ebrahimior Gradle:
899*53ff1f6bSSadaf Ebrahimi```groovy
900*53ff1f6bSSadaf Ebrahimicompile 'com.squareup:javapoet:1.12.1'
901*53ff1f6bSSadaf Ebrahimi```
902*53ff1f6bSSadaf Ebrahimi
903*53ff1f6bSSadaf EbrahimiSnapshots of the development version are available in [Sonatype's `snapshots` repository][snap].
904*53ff1f6bSSadaf Ebrahimi
905*53ff1f6bSSadaf Ebrahimi
906*53ff1f6bSSadaf Ebrahimi
907*53ff1f6bSSadaf EbrahimiLicense
908*53ff1f6bSSadaf Ebrahimi-------
909*53ff1f6bSSadaf Ebrahimi
910*53ff1f6bSSadaf Ebrahimi    Copyright 2015 Square, Inc.
911*53ff1f6bSSadaf Ebrahimi
912*53ff1f6bSSadaf Ebrahimi    Licensed under the Apache License, Version 2.0 (the "License");
913*53ff1f6bSSadaf Ebrahimi    you may not use this file except in compliance with the License.
914*53ff1f6bSSadaf Ebrahimi    You may obtain a copy of the License at
915*53ff1f6bSSadaf Ebrahimi
916*53ff1f6bSSadaf Ebrahimi       http://www.apache.org/licenses/LICENSE-2.0
917*53ff1f6bSSadaf Ebrahimi
918*53ff1f6bSSadaf Ebrahimi    Unless required by applicable law or agreed to in writing, software
919*53ff1f6bSSadaf Ebrahimi    distributed under the License is distributed on an "AS IS" BASIS,
920*53ff1f6bSSadaf Ebrahimi    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
921*53ff1f6bSSadaf Ebrahimi    See the License for the specific language governing permissions and
922*53ff1f6bSSadaf Ebrahimi    limitations under the License.
923*53ff1f6bSSadaf Ebrahimi
924*53ff1f6bSSadaf Ebrahimi
925*53ff1f6bSSadaf Ebrahimi
926*53ff1f6bSSadaf EbrahimiJavaWriter
927*53ff1f6bSSadaf Ebrahimi==========
928*53ff1f6bSSadaf Ebrahimi
929*53ff1f6bSSadaf EbrahimiJavaPoet is the successor to [JavaWriter][javawriter]. New projects should prefer JavaPoet because
930*53ff1f6bSSadaf Ebrahimiit has a stronger code model: it understands types and can manage imports automatically. JavaPoet is
931*53ff1f6bSSadaf Ebrahimialso better suited to composition: rather than streaming the contents of a `.java` file
932*53ff1f6bSSadaf Ebrahimitop-to-bottom in a single pass, a file can be assembled as a tree of declarations.
933*53ff1f6bSSadaf Ebrahimi
934*53ff1f6bSSadaf EbrahimiJavaWriter continues to be available in [GitHub][javawriter] and [Maven Central][javawriter_maven].
935*53ff1f6bSSadaf Ebrahimi
936*53ff1f6bSSadaf Ebrahimi
937*53ff1f6bSSadaf Ebrahimi [dl]: https://search.maven.org/remote_content?g=com.squareup&a=javapoet&v=LATEST
938*53ff1f6bSSadaf Ebrahimi [snap]: https://oss.sonatype.org/content/repositories/snapshots/com/squareup/javapoet/
939*53ff1f6bSSadaf Ebrahimi [javadoc]: https://square.github.io/javapoet/1.x/javapoet/
940*53ff1f6bSSadaf Ebrahimi [javawriter]: https://github.com/square/javapoet/tree/javawriter_2
941*53ff1f6bSSadaf Ebrahimi [javawriter_maven]: https://search.maven.org/#artifactdetails%7Ccom.squareup%7Cjavawriter%7C2.5.1%7Cjar
942*53ff1f6bSSadaf Ebrahimi [formatter]: https://developer.android.com/reference/java/util/Formatter.html
943*53ff1f6bSSadaf Ebrahimi [modifier]: https://docs.oracle.com/javase/8/docs/api/javax/lang/model/element/Modifier.html
944