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