{"id":13485589,"url":"https://github.com/square/javapoet","last_synced_at":"2025-12-17T19:42:24.214Z","repository":{"id":6716265,"uuid":"7961991","full_name":"square/javapoet","owner":"square","description":"A Java API for generating .java source files.","archived":true,"fork":false,"pushed_at":"2024-10-10T21:04:58.000Z","size":1954,"stargazers_count":10829,"open_issues_count":143,"forks_count":1376,"subscribers_count":347,"default_branch":"master","last_synced_at":"2024-11-17T12:53:07.914Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/square.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2013-02-01T16:56:30.000Z","updated_at":"2024-11-14T09:49:59.000Z","dependencies_parsed_at":"2023-12-02T00:27:05.405Z","dependency_job_id":"ea0cd7d1-41cd-4501-9c3e-2e343ea4d51c","html_url":"https://github.com/square/javapoet","commit_stats":{"total_commits":563,"total_committers":98,"mean_commits":5.744897959183674,"dds":0.7602131438721137,"last_synced_commit":"e48d418880076d72fab1a11196321efe3600053c"},"previous_names":["square/javawriter"],"tags_count":38,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/square%2Fjavapoet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/square%2Fjavapoet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/square%2Fjavapoet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/square%2Fjavapoet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/square","download_url":"https://codeload.github.com/square/javapoet/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245158521,"owners_count":20570194,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T18:00:27.184Z","updated_at":"2025-12-17T19:42:19.157Z","avatar_url":"https://github.com/square.png","language":"Java","readme":"JavaPoet\n========\n\n`JavaPoet` is a Java API for generating `.java` source files.\n\nSource file generation can be useful when doing things such as annotation processing or interacting\nwith metadata files (e.g., database schemas, protocol formats). By generating code, you eliminate\nthe need to write boilerplate while also keeping a single source of truth for the metadata.\n\n\nDeprecated\n----------\n\nAs of 2020-10-10, Square's JavaPoet project is deprecated. We're proud of our work but we haven't\nkept up on maintaining it.\n\nIf you'd like an alternative that supports the latest Java language features, one option is\n[Palantir's JavaPoet](https://github.com/palantir/javapoet).\n\nTo switch to that project, you'll need new Maven coordinates:\n\n```diff\n- javapoet = { module = \"com.squareup:javapoet\", version = \"1.13.0\" }\n+ javapoet = { module = \"com.palantir.javapoet:javapoet\", version = \"0.5.0\" }\n```\n\nAnd new imports:\n\n```\nsed -i \"\" \\\n  's/com.squareup.javapoet.\\([A-Za-z]*\\)/com.palantir.javapoet.\\1/g' \\\n  `find . -name \"*.kt\" -or -name \"*.java\"`\n```\n\nAnd you might need to track some API changes where fields became functions:\n\n```diff\n- javaFile.packageName\n+ javaFile.packageName()\n```\n\n### Example\n\nHere's a (boring) `HelloWorld` class:\n\n```java\npackage com.example.helloworld;\n\npublic final class HelloWorld {\n  public static void main(String[] args) {\n    System.out.println(\"Hello, JavaPoet!\");\n  }\n}\n```\n\nAnd this is the (exciting) code to generate it with JavaPoet:\n\n```java\nMethodSpec main = MethodSpec.methodBuilder(\"main\")\n    .addModifiers(Modifier.PUBLIC, Modifier.STATIC)\n    .returns(void.class)\n    .addParameter(String[].class, \"args\")\n    .addStatement(\"$T.out.println($S)\", System.class, \"Hello, JavaPoet!\")\n    .build();\n\nTypeSpec helloWorld = TypeSpec.classBuilder(\"HelloWorld\")\n    .addModifiers(Modifier.PUBLIC, Modifier.FINAL)\n    .addMethod(main)\n    .build();\n\nJavaFile javaFile = JavaFile.builder(\"com.example.helloworld\", helloWorld)\n    .build();\n\njavaFile.writeTo(System.out);\n```\n\nTo declare the main method, we've created a `MethodSpec` \"main\" configured with modifiers, return\ntype, parameters and code statements. We add the main method to a `HelloWorld` class, and then add\nthat to a `HelloWorld.java` file.\n\nIn this case we write the file to `System.out`, but we could also get it as a string\n(`JavaFile.toString()`) or write it to the file system (`JavaFile.writeTo()`).\n\nThe [Javadoc][javadoc] catalogs the complete JavaPoet API, which we explore below.\n\n### Code \u0026 Control Flow\n\nMost of JavaPoet's API uses plain old immutable Java objects. There's also builders, method chaining\nand varargs to make the API friendly. JavaPoet offers models for classes \u0026 interfaces (`TypeSpec`),\nfields (`FieldSpec`), methods \u0026 constructors (`MethodSpec`), parameters (`ParameterSpec`) and\nannotations (`AnnotationSpec`).\n\nBut the _body_ of methods and constructors is not modeled. There's no expression class, no\nstatement class or syntax tree nodes. Instead, JavaPoet uses strings for code blocks:\n\n```java\nMethodSpec main = MethodSpec.methodBuilder(\"main\")\n    .addCode(\"\"\n        + \"int total = 0;\\n\"\n        + \"for (int i = 0; i \u003c 10; i++) {\\n\"\n        + \"  total += i;\\n\"\n        + \"}\\n\")\n    .build();\n```\n\nWhich generates this:\n\n```java\nvoid main() {\n  int total = 0;\n  for (int i = 0; i \u003c 10; i++) {\n    total += i;\n  }\n}\n```\n\nThe manual semicolons, line wrapping, and indentation are tedious and so JavaPoet offers APIs to\nmake it easier. There's `addStatement()` which takes care of semicolons and newline, and\n`beginControlFlow()` + `endControlFlow()` which are used together for braces, newlines, and\nindentation:\n\n```java\nMethodSpec main = MethodSpec.methodBuilder(\"main\")\n    .addStatement(\"int total = 0\")\n    .beginControlFlow(\"for (int i = 0; i \u003c 10; i++)\")\n    .addStatement(\"total += i\")\n    .endControlFlow()\n    .build();\n```\n\nThis example is lame because the generated code is constant! Suppose instead of just adding 0 to 10,\nwe want to make the operation and range configurable. Here's a method that generates a method:\n\n```java\nprivate MethodSpec computeRange(String name, int from, int to, String op) {\n  return MethodSpec.methodBuilder(name)\n      .returns(int.class)\n      .addStatement(\"int result = 1\")\n      .beginControlFlow(\"for (int i = \" + from + \"; i \u003c \" + to + \"; i++)\")\n      .addStatement(\"result = result \" + op + \" i\")\n      .endControlFlow()\n      .addStatement(\"return result\")\n      .build();\n}\n```\n\nAnd here's what we get when we call `computeRange(\"multiply10to20\", 10, 20, \"*\")`:\n\n```java\nint multiply10to20() {\n  int result = 1;\n  for (int i = 10; i \u003c 20; i++) {\n    result = result * i;\n  }\n  return result;\n}\n```\n\nMethods generating methods! And since JavaPoet generates source instead of bytecode, you can\nread through it to make sure it's right.\n\nSome control flow statements, such as `if/else`, can have unlimited control flow possibilities.\nYou can handle those options using `nextControlFlow()`:\n\n```java\nMethodSpec main = MethodSpec.methodBuilder(\"main\")\n    .addStatement(\"long now = $T.currentTimeMillis()\", System.class)\n    .beginControlFlow(\"if ($T.currentTimeMillis() \u003c now)\", System.class)\n    .addStatement(\"$T.out.println($S)\", System.class, \"Time travelling, woo hoo!\")\n    .nextControlFlow(\"else if ($T.currentTimeMillis() == now)\", System.class)\n    .addStatement(\"$T.out.println($S)\", System.class, \"Time stood still!\")\n    .nextControlFlow(\"else\")\n    .addStatement(\"$T.out.println($S)\", System.class, \"Ok, time still moving forward\")\n    .endControlFlow()\n    .build();\n```\n\nWhich generates:\n\n```java\nvoid main() {\n  long now = System.currentTimeMillis();\n  if (System.currentTimeMillis() \u003c now)  {\n    System.out.println(\"Time travelling, woo hoo!\");\n  } else if (System.currentTimeMillis() == now) {\n    System.out.println(\"Time stood still!\");\n  } else {\n    System.out.println(\"Ok, time still moving forward\");\n  }\n}\n``` \n\nCatching exceptions using `try/catch` is also a use case for `nextControlFlow()`:\n\n```java\nMethodSpec main = MethodSpec.methodBuilder(\"main\")\n    .beginControlFlow(\"try\")\n    .addStatement(\"throw new Exception($S)\", \"Failed\")\n    .nextControlFlow(\"catch ($T e)\", Exception.class)\n    .addStatement(\"throw new $T(e)\", RuntimeException.class)\n    .endControlFlow()\n    .build();\n```\n\nWhich produces:\n\n```java\nvoid main() {\n  try {\n    throw new Exception(\"Failed\");\n  } catch (Exception e) {\n    throw new RuntimeException(e);\n  }\n}\n```\n\n### $L for Literals\n\nThe string-concatenation in calls to `beginControlFlow()` and `addStatement` is distracting. Too\nmany operators. To address this, JavaPoet offers a syntax inspired-by but incompatible-with\n[`String.format()`][formatter]. It accepts **`$L`** to emit a **literal** value in the output. This\nworks just like `Formatter`'s `%s`:\n\n```java\nprivate MethodSpec computeRange(String name, int from, int to, String op) {\n  return MethodSpec.methodBuilder(name)\n      .returns(int.class)\n      .addStatement(\"int result = 0\")\n      .beginControlFlow(\"for (int i = $L; i \u003c $L; i++)\", from, to)\n      .addStatement(\"result = result $L i\", op)\n      .endControlFlow()\n      .addStatement(\"return result\")\n      .build();\n}\n```\n\nLiterals are emitted directly to the output code with no escaping. Arguments for literals may be\nstrings, primitives, and a few JavaPoet types described below.\n\n### $S for Strings\n\nWhen emitting code that includes string literals, we can use **`$S`** to emit a **string**, complete\nwith wrapping quotation marks and escaping. Here's a program that emits 3 methods, each of which\nreturns its own name:\n\n```java\npublic static void main(String[] args) throws Exception {\n  TypeSpec helloWorld = TypeSpec.classBuilder(\"HelloWorld\")\n      .addModifiers(Modifier.PUBLIC, Modifier.FINAL)\n      .addMethod(whatsMyName(\"slimShady\"))\n      .addMethod(whatsMyName(\"eminem\"))\n      .addMethod(whatsMyName(\"marshallMathers\"))\n      .build();\n\n  JavaFile javaFile = JavaFile.builder(\"com.example.helloworld\", helloWorld)\n      .build();\n\n  javaFile.writeTo(System.out);\n}\n\nprivate static MethodSpec whatsMyName(String name) {\n  return MethodSpec.methodBuilder(name)\n      .returns(String.class)\n      .addStatement(\"return $S\", name)\n      .build();\n}\n```\n\nIn this case, using `$S` gives us quotation marks:\n\n```java\npublic final class HelloWorld {\n  String slimShady() {\n    return \"slimShady\";\n  }\n\n  String eminem() {\n    return \"eminem\";\n  }\n\n  String marshallMathers() {\n    return \"marshallMathers\";\n  }\n}\n```\n\n### $T for Types\n\nWe Java programmers love our types: they make our code easier to understand. And JavaPoet is on\nboard. It has rich built-in support for types, including automatic generation of `import`\nstatements. Just use **`$T`** to reference **types**:\n\n```java\nMethodSpec today = MethodSpec.methodBuilder(\"today\")\n    .returns(Date.class)\n    .addStatement(\"return new $T()\", Date.class)\n    .build();\n\nTypeSpec helloWorld = TypeSpec.classBuilder(\"HelloWorld\")\n    .addModifiers(Modifier.PUBLIC, Modifier.FINAL)\n    .addMethod(today)\n    .build();\n\nJavaFile javaFile = JavaFile.builder(\"com.example.helloworld\", helloWorld)\n    .build();\n\njavaFile.writeTo(System.out);\n```\n\nThat generates the following `.java` file, complete with the necessary `import`:\n\n```java\npackage com.example.helloworld;\n\nimport java.util.Date;\n\npublic final class HelloWorld {\n  Date today() {\n    return new Date();\n  }\n}\n```\n\nWe passed `Date.class` to reference a class that just-so-happens to be available when we're\ngenerating code. This doesn't need to be the case. Here's a similar example, but this one\nreferences a class that doesn't exist (yet):\n\n```java\nClassName hoverboard = ClassName.get(\"com.mattel\", \"Hoverboard\");\n\nMethodSpec today = MethodSpec.methodBuilder(\"tomorrow\")\n    .returns(hoverboard)\n    .addStatement(\"return new $T()\", hoverboard)\n    .build();\n```\n\nAnd that not-yet-existent class is imported as well:\n\n```java\npackage com.example.helloworld;\n\nimport com.mattel.Hoverboard;\n\npublic final class HelloWorld {\n  Hoverboard tomorrow() {\n    return new Hoverboard();\n  }\n}\n```\n\nThe `ClassName` type is very important, and you'll need it frequently when you're using JavaPoet.\nIt can identify any _declared_ class. Declared types are just the beginning of Java's rich type\nsystem: we also have arrays, parameterized types, wildcard types, and type variables. JavaPoet has\nclasses for building each of these:\n\n```java\nClassName hoverboard = ClassName.get(\"com.mattel\", \"Hoverboard\");\nClassName list = ClassName.get(\"java.util\", \"List\");\nClassName arrayList = ClassName.get(\"java.util\", \"ArrayList\");\nTypeName listOfHoverboards = ParameterizedTypeName.get(list, hoverboard);\n\nMethodSpec beyond = MethodSpec.methodBuilder(\"beyond\")\n    .returns(listOfHoverboards)\n    .addStatement(\"$T result = new $T\u003c\u003e()\", listOfHoverboards, arrayList)\n    .addStatement(\"result.add(new $T())\", hoverboard)\n    .addStatement(\"result.add(new $T())\", hoverboard)\n    .addStatement(\"result.add(new $T())\", hoverboard)\n    .addStatement(\"return result\")\n    .build();\n```\n\nJavaPoet will decompose each type and import its components where possible.\n\n```java\npackage com.example.helloworld;\n\nimport com.mattel.Hoverboard;\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic final class HelloWorld {\n  List\u003cHoverboard\u003e beyond() {\n    List\u003cHoverboard\u003e result = new ArrayList\u003c\u003e();\n    result.add(new Hoverboard());\n    result.add(new Hoverboard());\n    result.add(new Hoverboard());\n    return result;\n  }\n}\n```\n\n#### Import static\n\nJavaPoet supports `import static`. It does it via explicitly collecting type member names. Let's\nenhance the previous example with some static sugar:\n\n```java\n...\nClassName namedBoards = ClassName.get(\"com.mattel\", \"Hoverboard\", \"Boards\");\n\nMethodSpec beyond = MethodSpec.methodBuilder(\"beyond\")\n    .returns(listOfHoverboards)\n    .addStatement(\"$T result = new $T\u003c\u003e()\", listOfHoverboards, arrayList)\n    .addStatement(\"result.add($T.createNimbus(2000))\", hoverboard)\n    .addStatement(\"result.add($T.createNimbus(\\\"2001\\\"))\", hoverboard)\n    .addStatement(\"result.add($T.createNimbus($T.THUNDERBOLT))\", hoverboard, namedBoards)\n    .addStatement(\"$T.sort(result)\", Collections.class)\n    .addStatement(\"return result.isEmpty() ? $T.emptyList() : result\", Collections.class)\n    .build();\n\nTypeSpec hello = TypeSpec.classBuilder(\"HelloWorld\")\n    .addMethod(beyond)\n    .build();\n\nJavaFile.builder(\"com.example.helloworld\", hello)\n    .addStaticImport(hoverboard, \"createNimbus\")\n    .addStaticImport(namedBoards, \"*\")\n    .addStaticImport(Collections.class, \"*\")\n    .build();\n```\n\nJavaPoet will first add your `import static` block to the file as configured, match and mangle\nall calls accordingly and also import all other types as needed.\n\n```java\npackage com.example.helloworld;\n\nimport static com.mattel.Hoverboard.Boards.*;\nimport static com.mattel.Hoverboard.createNimbus;\nimport static java.util.Collections.*;\n\nimport com.mattel.Hoverboard;\nimport java.util.ArrayList;\nimport java.util.List;\n\nclass HelloWorld {\n  List\u003cHoverboard\u003e beyond() {\n    List\u003cHoverboard\u003e result = new ArrayList\u003c\u003e();\n    result.add(createNimbus(2000));\n    result.add(createNimbus(\"2001\"));\n    result.add(createNimbus(THUNDERBOLT));\n    sort(result);\n    return result.isEmpty() ? emptyList() : result;\n  }\n}\n```\n\n### $N for Names\n\nGenerated code is often self-referential. Use **`$N`** to refer to another generated declaration by\nits name. Here's a method that calls another:\n\n```java\npublic String byteToHex(int b) {\n  char[] result = new char[2];\n  result[0] = hexDigit((b \u003e\u003e\u003e 4) \u0026 0xf);\n  result[1] = hexDigit(b \u0026 0xf);\n  return new String(result);\n}\n\npublic char hexDigit(int i) {\n  return (char) (i \u003c 10 ? i + '0' : i - 10 + 'a');\n}\n```\n\nWhen generating the code above, we pass the `hexDigit()` method as an argument to the `byteToHex()`\nmethod using `$N`:\n\n```java\nMethodSpec hexDigit = MethodSpec.methodBuilder(\"hexDigit\")\n    .addParameter(int.class, \"i\")\n    .returns(char.class)\n    .addStatement(\"return (char) (i \u003c 10 ? i + '0' : i - 10 + 'a')\")\n    .build();\n\nMethodSpec byteToHex = MethodSpec.methodBuilder(\"byteToHex\")\n    .addParameter(int.class, \"b\")\n    .returns(String.class)\n    .addStatement(\"char[] result = new char[2]\")\n    .addStatement(\"result[0] = $N((b \u003e\u003e\u003e 4) \u0026 0xf)\", hexDigit)\n    .addStatement(\"result[1] = $N(b \u0026 0xf)\", hexDigit)\n    .addStatement(\"return new String(result)\")\n    .build();\n```\n\n### Code block format strings\n\nCode blocks may specify the values for their placeholders in a few ways. Only one style may be used\nfor each operation on a code block.\n\n#### Relative Arguments\n\nPass an argument value for each placeholder in the format string to `CodeBlock.add()`. In each\nexample, we generate code to say \"I ate 3 tacos\"\n\n```java\nCodeBlock.builder().add(\"I ate $L $L\", 3, \"tacos\")\n```\n\n#### Positional Arguments\n\nPlace an integer index (1-based) before the placeholder in the format string to specify which\n argument to use.\n\n```java\nCodeBlock.builder().add(\"I ate $2L $1L\", \"tacos\", 3)\n```\n\n#### Named Arguments\n\nUse the syntax `$argumentName:X` where `X` is the format character and call `CodeBlock.addNamed()`\nwith a map containing all argument keys in the format string. Argument names use characters in\n`a-z`, `A-Z`, `0-9`, and `_`, and must start with a lowercase character.\n\n```java\nMap\u003cString, Object\u003e map = new LinkedHashMap\u003c\u003e();\nmap.put(\"food\", \"tacos\");\nmap.put(\"count\", 3);\nCodeBlock.builder().addNamed(\"I ate $count:L $food:L\", map)\n```\n\n### Methods\n\nAll of the above methods have a code body. Use `Modifiers.ABSTRACT` to get a method without any\nbody. This is only legal if the enclosing class is either abstract or an interface.\n\n```java\nMethodSpec flux = MethodSpec.methodBuilder(\"flux\")\n    .addModifiers(Modifier.ABSTRACT, Modifier.PROTECTED)\n    .build();\n\nTypeSpec helloWorld = TypeSpec.classBuilder(\"HelloWorld\")\n    .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)\n    .addMethod(flux)\n    .build();\n```\n\nWhich generates this:\n\n```java\npublic abstract class HelloWorld {\n  protected abstract void flux();\n}\n```\n\nThe other modifiers work where permitted. Note that when specifying modifiers, JavaPoet uses\n[`javax.lang.model.element.Modifier`][modifier], a class that is not available on Android. This\nlimitation applies to code-generating-code only; the output code runs everywhere: JVMs, Android,\nand GWT.\n\nMethods also have parameters, exceptions, varargs, Javadoc, annotations, type variables, and a\nreturn type. All of these are configured with `MethodSpec.Builder`.\n\n### Constructors\n\n`MethodSpec` is a slight misnomer; it can also be used for constructors:\n\n```java\nMethodSpec flux = MethodSpec.constructorBuilder()\n    .addModifiers(Modifier.PUBLIC)\n    .addParameter(String.class, \"greeting\")\n    .addStatement(\"this.$N = $N\", \"greeting\", \"greeting\")\n    .build();\n\nTypeSpec helloWorld = TypeSpec.classBuilder(\"HelloWorld\")\n    .addModifiers(Modifier.PUBLIC)\n    .addField(String.class, \"greeting\", Modifier.PRIVATE, Modifier.FINAL)\n    .addMethod(flux)\n    .build();\n```\n\nWhich generates this:\n\n```java\npublic class HelloWorld {\n  private final String greeting;\n\n  public HelloWorld(String greeting) {\n    this.greeting = greeting;\n  }\n}\n```\n\nFor the most part, constructors work just like methods. When emitting code, JavaPoet will place\nconstructors before methods in the output file.\n\n### Parameters\n\nDeclare parameters on methods and constructors with either `ParameterSpec.builder()` or\n`MethodSpec`'s convenient `addParameter()` API:\n\n```java\nParameterSpec android = ParameterSpec.builder(String.class, \"android\")\n    .addModifiers(Modifier.FINAL)\n    .build();\n\nMethodSpec welcomeOverlords = MethodSpec.methodBuilder(\"welcomeOverlords\")\n    .addParameter(android)\n    .addParameter(String.class, \"robot\", Modifier.FINAL)\n    .build();\n```\n\nThough the code above to generate `android` and `robot` parameters is different, the output is the\nsame:\n\n```java\nvoid welcomeOverlords(final String android, final String robot) {\n}\n```\n\nThe extended `Builder` form is necessary when the parameter has annotations (such as `@Nullable`).\n\n### Fields\n\nLike parameters, fields can be created either with builders or by using convenient helper methods:\n\n```java\nFieldSpec android = FieldSpec.builder(String.class, \"android\")\n    .addModifiers(Modifier.PRIVATE, Modifier.FINAL)\n    .build();\n\nTypeSpec helloWorld = TypeSpec.classBuilder(\"HelloWorld\")\n    .addModifiers(Modifier.PUBLIC)\n    .addField(android)\n    .addField(String.class, \"robot\", Modifier.PRIVATE, Modifier.FINAL)\n    .build();\n```\n\nWhich generates:\n\n```java\npublic class HelloWorld {\n  private final String android;\n\n  private final String robot;\n}\n```\n\nThe extended `Builder` form is necessary when a field has Javadoc, annotations, or a field\ninitializer. Field initializers use the same [`String.format()`][formatter]-like syntax as the code\nblocks above:\n\n```java\nFieldSpec android = FieldSpec.builder(String.class, \"android\")\n    .addModifiers(Modifier.PRIVATE, Modifier.FINAL)\n    .initializer(\"$S + $L\", \"Lollipop v.\", 5.0d)\n    .build();\n```\n\nWhich generates:\n\n```java\nprivate final String android = \"Lollipop v.\" + 5.0;\n```\n\n### Interfaces\n\nJavaPoet has no trouble with interfaces. Note that interface methods must always be `PUBLIC\nABSTRACT` and interface fields must always be `PUBLIC STATIC FINAL`. These modifiers are necessary\nwhen defining the interface:\n\n```java\nTypeSpec helloWorld = TypeSpec.interfaceBuilder(\"HelloWorld\")\n    .addModifiers(Modifier.PUBLIC)\n    .addField(FieldSpec.builder(String.class, \"ONLY_THING_THAT_IS_CONSTANT\")\n        .addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)\n        .initializer(\"$S\", \"change\")\n        .build())\n    .addMethod(MethodSpec.methodBuilder(\"beep\")\n        .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)\n        .build())\n    .build();\n```\n\nBut these modifiers are omitted when the code is generated. These are the defaults so we don't need\nto include them for `javac`'s benefit!\n\n```java\npublic interface HelloWorld {\n  String ONLY_THING_THAT_IS_CONSTANT = \"change\";\n\n  void beep();\n}\n```\n\n### Enums\n\nUse `enumBuilder` to create the enum type, and `addEnumConstant()` for each value:\n\n```java\nTypeSpec helloWorld = TypeSpec.enumBuilder(\"Roshambo\")\n    .addModifiers(Modifier.PUBLIC)\n    .addEnumConstant(\"ROCK\")\n    .addEnumConstant(\"SCISSORS\")\n    .addEnumConstant(\"PAPER\")\n    .build();\n```\n\nTo generate this:\n\n```java\npublic enum Roshambo {\n  ROCK,\n\n  SCISSORS,\n\n  PAPER\n}\n```\n\nFancy enums are supported, where the enum values override methods or call a superclass constructor.\nHere's a comprehensive example:\n\n```java\nTypeSpec helloWorld = TypeSpec.enumBuilder(\"Roshambo\")\n    .addModifiers(Modifier.PUBLIC)\n    .addEnumConstant(\"ROCK\", TypeSpec.anonymousClassBuilder(\"$S\", \"fist\")\n        .addMethod(MethodSpec.methodBuilder(\"toString\")\n            .addAnnotation(Override.class)\n            .addModifiers(Modifier.PUBLIC)\n            .addStatement(\"return $S\", \"avalanche!\")\n            .returns(String.class)\n            .build())\n        .build())\n    .addEnumConstant(\"SCISSORS\", TypeSpec.anonymousClassBuilder(\"$S\", \"peace\")\n        .build())\n    .addEnumConstant(\"PAPER\", TypeSpec.anonymousClassBuilder(\"$S\", \"flat\")\n        .build())\n    .addField(String.class, \"handsign\", Modifier.PRIVATE, Modifier.FINAL)\n    .addMethod(MethodSpec.constructorBuilder()\n        .addParameter(String.class, \"handsign\")\n        .addStatement(\"this.$N = $N\", \"handsign\", \"handsign\")\n        .build())\n    .build();\n```\n\nWhich generates this:\n\n```java\npublic enum Roshambo {\n  ROCK(\"fist\") {\n    @Override\n    public String toString() {\n      return \"avalanche!\";\n    }\n  },\n\n  SCISSORS(\"peace\"),\n\n  PAPER(\"flat\");\n\n  private final String handsign;\n\n  Roshambo(String handsign) {\n    this.handsign = handsign;\n  }\n}\n```\n\n### Anonymous Inner Classes\n\nIn the enum code, we used `TypeSpec.anonymousInnerClass()`. Anonymous inner classes can also be used in\ncode blocks. They are values that can be referenced with `$L`:\n\n```java\nTypeSpec comparator = TypeSpec.anonymousClassBuilder(\"\")\n    .addSuperinterface(ParameterizedTypeName.get(Comparator.class, String.class))\n    .addMethod(MethodSpec.methodBuilder(\"compare\")\n        .addAnnotation(Override.class)\n        .addModifiers(Modifier.PUBLIC)\n        .addParameter(String.class, \"a\")\n        .addParameter(String.class, \"b\")\n        .returns(int.class)\n        .addStatement(\"return $N.length() - $N.length()\", \"a\", \"b\")\n        .build())\n    .build();\n\nTypeSpec helloWorld = TypeSpec.classBuilder(\"HelloWorld\")\n    .addMethod(MethodSpec.methodBuilder(\"sortByLength\")\n        .addParameter(ParameterizedTypeName.get(List.class, String.class), \"strings\")\n        .addStatement(\"$T.sort($N, $L)\", Collections.class, \"strings\", comparator)\n        .build())\n    .build();\n```\n\nThis generates a method that contains a class that contains a method:\n\n```java\nvoid sortByLength(List\u003cString\u003e strings) {\n  Collections.sort(strings, new Comparator\u003cString\u003e() {\n    @Override\n    public int compare(String a, String b) {\n      return a.length() - b.length();\n    }\n  });\n}\n```\n\nOne particularly tricky part of defining anonymous inner classes is the arguments to the superclass\nconstructor. In the above code we're passing the empty string for no arguments:\n`TypeSpec.anonymousClassBuilder(\"\")`. To pass different parameters use JavaPoet's code block\nsyntax with commas to separate arguments.\n\n\n### Annotations\n\nSimple annotations are easy:\n\n```java\nMethodSpec toString = MethodSpec.methodBuilder(\"toString\")\n    .addAnnotation(Override.class)\n    .returns(String.class)\n    .addModifiers(Modifier.PUBLIC)\n    .addStatement(\"return $S\", \"Hoverboard\")\n    .build();\n```\n\nWhich generates this method with an `@Override` annotation:\n\n```java\n  @Override\n  public String toString() {\n    return \"Hoverboard\";\n  }\n```\n\nUse `AnnotationSpec.builder()` to set properties on annotations:\n\n```java\nMethodSpec logRecord = MethodSpec.methodBuilder(\"recordEvent\")\n    .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)\n    .addAnnotation(AnnotationSpec.builder(Headers.class)\n        .addMember(\"accept\", \"$S\", \"application/json; charset=utf-8\")\n        .addMember(\"userAgent\", \"$S\", \"Square Cash\")\n        .build())\n    .addParameter(LogRecord.class, \"logRecord\")\n    .returns(LogReceipt.class)\n    .build();\n```\n\nWhich generates this annotation with `accept` and `userAgent` properties:\n\n```java\n@Headers(\n    accept = \"application/json; charset=utf-8\",\n    userAgent = \"Square Cash\"\n)\nLogReceipt recordEvent(LogRecord logRecord);\n```\n\nWhen you get fancy, annotation values can be annotations themselves. Use `$L` for embedded\nannotations:\n\n```java\nMethodSpec logRecord = MethodSpec.methodBuilder(\"recordEvent\")\n    .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)\n    .addAnnotation(AnnotationSpec.builder(HeaderList.class)\n        .addMember(\"value\", \"$L\", AnnotationSpec.builder(Header.class)\n            .addMember(\"name\", \"$S\", \"Accept\")\n            .addMember(\"value\", \"$S\", \"application/json; charset=utf-8\")\n            .build())\n        .addMember(\"value\", \"$L\", AnnotationSpec.builder(Header.class)\n            .addMember(\"name\", \"$S\", \"User-Agent\")\n            .addMember(\"value\", \"$S\", \"Square Cash\")\n            .build())\n        .build())\n    .addParameter(LogRecord.class, \"logRecord\")\n    .returns(LogReceipt.class)\n    .build();\n```\n\nWhich generates this:\n\n```java\n@HeaderList({\n    @Header(name = \"Accept\", value = \"application/json; charset=utf-8\"),\n    @Header(name = \"User-Agent\", value = \"Square Cash\")\n})\nLogReceipt recordEvent(LogRecord logRecord);\n```\n\nNote that you can call `addMember()` multiple times with the same property name to populate a list\nof values for that property.\n\n### Javadoc\n\nFields, methods and types can be documented with Javadoc:\n\n```java\nMethodSpec dismiss = MethodSpec.methodBuilder(\"dismiss\")\n    .addJavadoc(\"Hides {@code message} from the caller's history. Other\\n\"\n        + \"participants in the conversation will continue to see the\\n\"\n        + \"message in their own history unless they also delete it.\\n\")\n    .addJavadoc(\"\\n\")\n    .addJavadoc(\"\u003cp\u003eUse {@link #delete($T)} to delete the entire\\n\"\n        + \"conversation for all participants.\\n\", Conversation.class)\n    .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)\n    .addParameter(Message.class, \"message\")\n    .build();\n```\n\nWhich generates this:\n\n```java\n  /**\n   * Hides {@code message} from the caller's history. Other\n   * participants in the conversation will continue to see the\n   * message in their own history unless they also delete it.\n   *\n   * \u003cp\u003eUse {@link #delete(Conversation)} to delete the entire\n   * conversation for all participants.\n   */\n  void dismiss(Message message);\n```\n\nUse `$T` when referencing types in Javadoc to get automatic imports.\n\nDownload\n--------\n\nDownload [the latest .jar][dl] or depend via Maven:\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003ecom.squareup\u003c/groupId\u003e\n  \u003cartifactId\u003ejavapoet\u003c/artifactId\u003e\n  \u003cversion\u003e1.13.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\nor Gradle:\n```groovy\ncompile 'com.squareup:javapoet:1.13.0'\n```\n\nSnapshots of the development version are available in [Sonatype's `snapshots` repository][snap].\n\n\n\nLicense\n-------\n\n    Copyright 2015 Square, Inc.\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n\n\n\nJavaWriter\n==========\n\nJavaPoet is the successor to [JavaWriter][javawriter]. New projects should prefer JavaPoet because\nit has a stronger code model: it understands types and can manage imports automatically. JavaPoet is\nalso better suited to composition: rather than streaming the contents of a `.java` file\ntop-to-bottom in a single pass, a file can be assembled as a tree of declarations.\n\nJavaWriter continues to be available in [GitHub][javawriter] and [Maven Central][javawriter_maven].\n\n\n [dl]: https://search.maven.org/remote_content?g=com.squareup\u0026a=javapoet\u0026v=LATEST\n [snap]: https://oss.sonatype.org/content/repositories/snapshots/com/squareup/javapoet/\n [javadoc]: https://square.github.io/javapoet/1.x/javapoet/\n [javawriter]: https://github.com/square/javapoet/tree/javawriter_2\n [javawriter_maven]: https://search.maven.org/#artifactdetails%7Ccom.squareup%7Cjavawriter%7C2.5.1%7Cjar\n [formatter]: https://developer.android.com/reference/java/util/Formatter.html\n [modifier]: https://docs.oracle.com/javase/8/docs/api/javax/lang/model/element/Modifier.html\n","funding_links":[],"categories":["Projects","Java","\u003ca name=\"Java\"\u003e\u003c/a\u003eJava","项目","I. Development","常用框架\\\u0026第三方库","Annotation","Metaprogramming"],"sub_categories":["Code Generators","代码生成器","8. Code generation and changing byte code"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsquare%2Fjavapoet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsquare%2Fjavapoet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsquare%2Fjavapoet/lists"}