• Home
Name Date Size #Lines LOC

..--

.buildscript/03-May-2024-3726

src/03-May-2024-10,7308,495

.gitignoreD03-May-2024150 2418

.travis.ymlD03-May-20241.3 KiB4736

Android.bpD03-May-2024737 2219

CHANGELOG.mdD03-May-202410.6 KiB303202

CONTRIBUTING.mdD03-May-2024722 1812

LICENSED03-May-202411.1 KiB203169

LICENSE.txtD03-May-202411.1 KiB203169

METADATAD03-May-2024329 1815

MODULE_LICENSE_APACHE2D03-May-20240

NOTICED03-May-202411.1 KiB203169

OWNERSD03-May-202462 43

README.mdD03-May-202425.8 KiB890693

checkstyle.xmlD03-May-20245.4 KiB14985

pom.xmlD03-May-20244.7 KiB160144

README.md

1JavaPoet
2========
3
4`JavaPoet` is a Java API for generating `.java` source files.
5
6Source file generation can be useful when doing things such as annotation processing or interacting
7with metadata files (e.g., database schemas, protocol formats). By generating code, you eliminate
8the need to write boilerplate while also keeping a single source of truth for the metadata.
9
10
11### Example
12
13Here's a (boring) `HelloWorld` class:
14
15```java
16package com.example.helloworld;
17
18public final class HelloWorld {
19  public static void main(String[] args) {
20    System.out.println("Hello, JavaPoet!");
21  }
22}
23```
24
25And this is the (exciting) code to generate it with JavaPoet:
26
27```java
28MethodSpec 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
35TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
36    .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
37    .addMethod(main)
38    .build();
39
40JavaFile javaFile = JavaFile.builder("com.example.helloworld", helloWorld)
41    .build();
42
43javaFile.writeTo(System.out);
44```
45
46To declare the main method, we've created a `MethodSpec` "main" configured with modifiers, return
47type, parameters and code statements. We add the main method to a `HelloWorld` class, and then add
48that to a `HelloWorld.java` file.
49
50In 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
53The [Javadoc][javadoc] catalogs the complete JavaPoet API, which we explore below.
54
55### Code & Control Flow
56
57Most of JavaPoet's API uses plain old immutable Java objects. There's also builders, method chaining
58and varargs to make the API friendly. JavaPoet offers models for classes & interfaces (`TypeSpec`),
59fields (`FieldSpec`), methods & constructors (`MethodSpec`), parameters (`ParameterSpec`) and
60annotations (`AnnotationSpec`).
61
62But the _body_ of methods and constructors is not modeled. There's no expression class, no
63statement class or syntax tree nodes. Instead, JavaPoet uses strings for code blocks:
64
65```java
66MethodSpec 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
75Which generates this:
76
77```java
78void main() {
79  int total = 0;
80  for (int i = 0; i < 10; i++) {
81    total += i;
82  }
83}
84```
85
86The manual semicolons, line wrapping, and indentation are tedious and so JavaPoet offers APIs to
87make it easier. There's `addStatement()` which takes care of semicolons and newline, and
88`beginControlFlow()` + `endControlFlow()` which are used together for braces, newlines, and
89indentation:
90
91```java
92MethodSpec 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
100This example is lame because the generated code is constant! Suppose instead of just adding 0 to 10,
101we want to make the operation and range configurable. Here's a method that generates a method:
102
103```java
104private 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
116And here's what we get when we call `computeRange("multiply10to20", 10, 20, "*")`:
117
118```java
119int multiply10to20() {
120  int result = 1;
121  for (int i = 10; i < 20; i++) {
122    result = result * i;
123  }
124  return result;
125}
126```
127
128Methods generating methods! And since JavaPoet generates source instead of bytecode, you can
129read through it to make sure it's right.
130
131
132### $L for Literals
133
134The string-concatenation in calls to `beginControlFlow()` and `addStatement` is distracting. Too
135many 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
137works just like `Formatter`'s `%s`:
138
139```java
140private 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
152Literals are emitted directly to the output code with no escaping. Arguments for literals may be
153strings, primitives, and a few JavaPoet types described below.
154
155### $S for Strings
156
157When emitting code that includes string literals, we can use **`$S`** to emit a **string**, complete
158with wrapping quotation marks and escaping. Here's a program that emits 3 methods, each of which
159returns its own name:
160
161```java
162public 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
176private static MethodSpec whatsMyName(String name) {
177  return MethodSpec.methodBuilder(name)
178      .returns(String.class)
179      .addStatement("return $S", name)
180      .build();
181}
182```
183
184In this case, using `$S` gives us quotation marks:
185
186```java
187public 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
204We Java programmers love our types: they make our code easier to understand. And JavaPoet is on
205board. It has rich built-in support for types, including automatic generation of `import`
206statements. Just use **`$T`** to reference **types**:
207
208```java
209MethodSpec today = MethodSpec.methodBuilder("today")
210    .returns(Date.class)
211    .addStatement("return new $T()", Date.class)
212    .build();
213
214TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
215    .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
216    .addMethod(today)
217    .build();
218
219JavaFile javaFile = JavaFile.builder("com.example.helloworld", helloWorld)
220    .build();
221
222javaFile.writeTo(System.out);
223```
224
225That generates the following `.java` file, complete with the necessary `import`:
226
227```java
228package com.example.helloworld;
229
230import java.util.Date;
231
232public final class HelloWorld {
233  Date today() {
234    return new Date();
235  }
236}
237```
238
239We passed `Date.class` to reference a class that just-so-happens to be available when we're
240generating code. This doesn't need to be the case. Here's a similar example, but this one
241references a class that doesn't exist (yet):
242
243```java
244ClassName hoverboard = ClassName.get("com.mattel", "Hoverboard");
245
246MethodSpec today = MethodSpec.methodBuilder("tomorrow")
247    .returns(hoverboard)
248    .addStatement("return new $T()", hoverboard)
249    .build();
250```
251
252And that not-yet-existent class is imported as well:
253
254```java
255package com.example.helloworld;
256
257import com.mattel.Hoverboard;
258
259public final class HelloWorld {
260  Hoverboard tomorrow() {
261    return new Hoverboard();
262  }
263}
264```
265
266The `ClassName` type is very important, and you'll need it frequently when you're using JavaPoet.
267It can identify any _declared_ class. Declared types are just the beginning of Java's rich type
268system: we also have arrays, parameterized types, wildcard types, and type variables. JavaPoet has
269classes for building each of these:
270
271```java
272ClassName hoverboard = ClassName.get("com.mattel", "Hoverboard");
273ClassName list = ClassName.get("java.util", "List");
274ClassName arrayList = ClassName.get("java.util", "ArrayList");
275TypeName listOfHoverboards = ParameterizedTypeName.get(list, hoverboard);
276
277MethodSpec 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
287JavaPoet will decompose each type and import its components where possible.
288
289```java
290package com.example.helloworld;
291
292import com.mattel.Hoverboard;
293import java.util.ArrayList;
294import java.util.List;
295
296public 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
309JavaPoet supports `import static`. It does it via explicitly collecting type member names. Let's
310enhance the previous example with some static sugar:
311
312```java
313...
314ClassName namedBoards = ClassName.get("com.mattel", "Hoverboard", "Boards");
315
316MethodSpec 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
326TypeSpec hello = TypeSpec.classBuilder("HelloWorld")
327    .addMethod(beyond)
328    .build();
329
330JavaFile.builder("com.example.helloworld", hello)
331    .addStaticImport(hoverboard, "createNimbus")
332    .addStaticImport(namedBoards, "*")
333    .addStaticImport(Collections.class, "*")
334    .build();
335```
336
337JavaPoet will first add your `import static` block to the file as configured, match and mangle
338all calls accordingly and also import all other types as needed.
339
340```java
341package com.example.helloworld;
342
343import static com.mattel.Hoverboard.Boards.*;
344import static com.mattel.Hoverboard.createNimbus;
345import static java.util.Collections.*;
346
347import com.mattel.Hoverboard;
348import java.util.ArrayList;
349import java.util.List;
350
351class 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
365Generated code is often self-referential. Use **`$N`** to refer to another generated declaration by
366its name. Here's a method that calls another:
367
368```java
369public 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
376public char hexDigit(int i) {
377  return (char) (i < 10 ? i + '0' : i - 10 + 'a');
378}
379```
380
381When generating the code above, we pass the `hexDigit()` method as an argument to the `byteToHex()`
382method using `$N`:
383
384```java
385MethodSpec 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
391MethodSpec 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
403Code blocks may specify the values for their placeholders in a few ways. Only one style may be used
404for each operation on a code block.
405
406#### Relative Arguments
407
408Pass an argument value for each placeholder in the format string to `CodeBlock.add()`. In each
409example, we generate code to say "I ate 3 tacos"
410
411```java
412CodeBlock.builder().add("I ate $L $L", 3, "tacos")
413```
414
415#### Positional Arguments
416
417Place an integer index (1-based) before the placeholder in the format string to specify which
418 argument to use.
419
420```java
421CodeBlock.builder().add("I ate $2L $1L", "tacos", 3)
422```
423
424#### Named Arguments
425
426Use the syntax `$argumentName:X` where `X` is the format character and call `CodeBlock.addNamed()`
427with 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
431Map<String, Object> map = new LinkedHashMap<>();
432map.put("food", "tacos");
433map.put("count", 3);
434CodeBlock.builder().addNamed("I ate $count:L $food:L", map)
435```
436
437### Methods
438
439All of the above methods have a code body. Use `Modifiers.ABSTRACT` to get a method without any
440body. This is only legal if the enclosing class is either abstract or an interface.
441
442```java
443MethodSpec flux = MethodSpec.methodBuilder("flux")
444    .addModifiers(Modifier.ABSTRACT, Modifier.PROTECTED)
445    .build();
446
447TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
448    .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
449    .addMethod(flux)
450    .build();
451```
452
453Which generates this:
454
455```java
456public abstract class HelloWorld {
457  protected abstract void flux();
458}
459```
460
461The 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
463limitation applies to code-generating-code only; the output code runs everywhere: JVMs, Android,
464and GWT.
465
466Methods also have parameters, exceptions, varargs, Javadoc, annotations, type variables, and a
467return 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
474MethodSpec flux = MethodSpec.constructorBuilder()
475    .addModifiers(Modifier.PUBLIC)
476    .addParameter(String.class, "greeting")
477    .addStatement("this.$N = $N", "greeting", "greeting")
478    .build();
479
480TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
481    .addModifiers(Modifier.PUBLIC)
482    .addField(String.class, "greeting", Modifier.PRIVATE, Modifier.FINAL)
483    .addMethod(flux)
484    .build();
485```
486
487Which generates this:
488
489```java
490public class HelloWorld {
491  private final String greeting;
492
493  public HelloWorld(String greeting) {
494    this.greeting = greeting;
495  }
496}
497```
498
499For the most part, constructors work just like methods. When emitting code, JavaPoet will place
500constructors before methods in the output file.
501
502### Parameters
503
504Declare parameters on methods and constructors with either `ParameterSpec.builder()` or
505`MethodSpec`'s convenient `addParameter()` API:
506
507```java
508ParameterSpec android = ParameterSpec.builder(String.class, "android")
509    .addModifiers(Modifier.FINAL)
510    .build();
511
512MethodSpec welcomeOverlords = MethodSpec.methodBuilder("welcomeOverlords")
513    .addParameter(android)
514    .addParameter(String.class, "robot", Modifier.FINAL)
515    .build();
516```
517
518Though the code above to generate `android` and `robot` parameters is different, the output is the
519same:
520
521```java
522void welcomeOverlords(final String android, final String robot) {
523}
524```
525
526The extended `Builder` form is necessary when the parameter has annotations (such as `@Nullable`).
527
528### Fields
529
530Like parameters, fields can be created either with builders or by using convenient helper methods:
531
532```java
533FieldSpec android = FieldSpec.builder(String.class, "android")
534    .addModifiers(Modifier.PRIVATE, Modifier.FINAL)
535    .build();
536
537TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
538    .addModifiers(Modifier.PUBLIC)
539    .addField(android)
540    .addField(String.class, "robot", Modifier.PRIVATE, Modifier.FINAL)
541    .build();
542```
543
544Which generates:
545
546```java
547public class HelloWorld {
548  private final String android;
549
550  private final String robot;
551}
552```
553
554The extended `Builder` form is necessary when a field has Javadoc, annotations, or a field
555initializer. Field initializers use the same [`String.format()`][formatter]-like syntax as the code
556blocks above:
557
558```java
559FieldSpec android = FieldSpec.builder(String.class, "android")
560    .addModifiers(Modifier.PRIVATE, Modifier.FINAL)
561    .initializer("$S + $L", "Lollipop v.", 5.0d)
562    .build();
563```
564
565Which generates:
566
567```java
568private final String android = "Lollipop v." + 5.0;
569```
570
571### Interfaces
572
573JavaPoet has no trouble with interfaces. Note that interface methods must always be `PUBLIC
574ABSTRACT` and interface fields must always be `PUBLIC STATIC FINAL`. These modifiers are necessary
575when defining the interface:
576
577```java
578TypeSpec 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
590But these modifiers are omitted when the code is generated. These are the defaults so we don't need
591to include them for `javac`'s benefit!
592
593```java
594public interface HelloWorld {
595  String ONLY_THING_THAT_IS_CONSTANT = "change";
596
597  void beep();
598}
599```
600
601### Enums
602
603Use `enumBuilder` to create the enum type, and `addEnumConstant()` for each value:
604
605```java
606TypeSpec helloWorld = TypeSpec.enumBuilder("Roshambo")
607    .addModifiers(Modifier.PUBLIC)
608    .addEnumConstant("ROCK")
609    .addEnumConstant("SCISSORS")
610    .addEnumConstant("PAPER")
611    .build();
612```
613
614To generate this:
615
616```java
617public enum Roshambo {
618  ROCK,
619
620  SCISSORS,
621
622  PAPER
623}
624```
625
626Fancy enums are supported, where the enum values override methods or call a superclass constructor.
627Here's a comprehensive example:
628
629```java
630TypeSpec 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
652Which generates this:
653
654```java
655public 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
677In the enum code, we used `Types.anonymousInnerClass()`. Anonymous inner classes can also be used in
678code blocks. They are values that can be referenced with `$L`:
679
680```java
681TypeSpec 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
693TypeSpec 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
701This generates a method that contains a class that contains a method:
702
703```java
704void 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
714One particularly tricky part of defining anonymous inner classes is the arguments to the superclass
715constructor. 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
717syntax with commas to separate arguments.
718
719
720### Annotations
721
722Simple annotations are easy:
723
724```java
725MethodSpec 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
733Which generates this method with an `@Override` annotation:
734
735```java
736  @Override
737  public String toString() {
738    return "Hoverboard";
739  }
740```
741
742Use `AnnotationSpec.builder()` to set properties on annotations:
743
744```java
745MethodSpec 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
756Which 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)
763LogReceipt recordEvent(LogRecord logRecord);
764```
765
766When you get fancy, annotation values can be annotations themselves. Use `$L` for embedded
767annotations:
768
769```java
770MethodSpec 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
787Which 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})
794LogReceipt recordEvent(LogRecord logRecord);
795```
796
797Note that you can call `addMember()` multiple times with the same property name to populate a list
798of values for that property.
799
800### Javadoc
801
802Fields, methods and types can be documented with Javadoc:
803
804```java
805MethodSpec 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
817Which 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
831Use `$T` when referencing types in Javadoc to get automatic imports.
832
833Download
834--------
835
836Download [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```
844or Gradle:
845```groovy
846compile 'com.squareup:javapoet:1.11.1'
847```
848
849Snapshots of the development version are available in [Sonatype's `snapshots` repository][snap].
850
851
852
853License
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
872JavaWriter
873==========
874
875JavaPoet is the successor to [JavaWriter][javawriter]. New projects should prefer JavaPoet because
876it has a stronger code model: it understands types and can manage imports automatically. JavaPoet is
877also better suited to composition: rather than streaming the contents of a `.java` file
878top-to-bottom in a single pass, a file can be assembled as a tree of declarations.
879
880JavaWriter 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