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