A Java API for generating .java source files.

Overview

JavaPoet

JavaPoet is a Java API for generating .java source files.

Source file generation can be useful when doing things such as annotation processing or interacting with metadata files (e.g., database schemas, protocol formats). By generating code, you eliminate the need to write boilerplate while also keeping a single source of truth for the metadata.

Example

Here's a (boring) HelloWorld class:

package com.example.helloworld;

public final class HelloWorld {
  public static void main(String[] args) {
    System.out.println("Hello, JavaPoet!");
  }
}

And this is the (exciting) code to generate it with JavaPoet:

MethodSpec main = MethodSpec.methodBuilder("main")
    .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
    .returns(void.class)
    .addParameter(String[].class, "args")
    .addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!")
    .build();

TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
    .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
    .addMethod(main)
    .build();

JavaFile javaFile = JavaFile.builder("com.example.helloworld", helloWorld)
    .build();

javaFile.writeTo(System.out);

To declare the main method, we've created a MethodSpec "main" configured with modifiers, return type, parameters and code statements. We add the main method to a HelloWorld class, and then add that to a HelloWorld.java file.

In this case we write the file to System.out, but we could also get it as a string (JavaFile.toString()) or write it to the file system (JavaFile.writeTo()).

The Javadoc catalogs the complete JavaPoet API, which we explore below.

Code & Control Flow

Most of JavaPoet's API uses plain old immutable Java objects. There's also builders, method chaining and varargs to make the API friendly. JavaPoet offers models for classes & interfaces (TypeSpec), fields (FieldSpec), methods & constructors (MethodSpec), parameters (ParameterSpec) and annotations (AnnotationSpec).

But the body of methods and constructors is not modeled. There's no expression class, no statement class or syntax tree nodes. Instead, JavaPoet uses strings for code blocks:

MethodSpec main = MethodSpec.methodBuilder("main")
    .addCode(""
        + "int total = 0;\n"
        + "for (int i = 0; i < 10; i++) {\n"
        + "  total += i;\n"
        + "}\n")
    .build();

Which generates this:

void main() {
  int total = 0;
  for (int i = 0; i < 10; i++) {
    total += i;
  }
}

The manual semicolons, line wrapping, and indentation are tedious and so JavaPoet offers APIs to make it easier. There's addStatement() which takes care of semicolons and newline, and beginControlFlow() + endControlFlow() which are used together for braces, newlines, and indentation:

MethodSpec main = MethodSpec.methodBuilder("main")
    .addStatement("int total = 0")
    .beginControlFlow("for (int i = 0; i < 10; i++)")
    .addStatement("total += i")
    .endControlFlow()
    .build();

This example is lame because the generated code is constant! Suppose instead of just adding 0 to 10, we want to make the operation and range configurable. Here's a method that generates a method:

private MethodSpec computeRange(String name, int from, int to, String op) {
  return MethodSpec.methodBuilder(name)
      .returns(int.class)
      .addStatement("int result = 1")
      .beginControlFlow("for (int i = " + from + "; i < " + to + "; i++)")
      .addStatement("result = result " + op + " i")
      .endControlFlow()
      .addStatement("return result")
      .build();
}

And here's what we get when we call computeRange("multiply10to20", 10, 20, "*"):

int multiply10to20() {
  int result = 1;
  for (int i = 10; i < 20; i++) {
    result = result * i;
  }
  return result;
}

Methods generating methods! And since JavaPoet generates source instead of bytecode, you can read through it to make sure it's right.

Some control flow statements, such as if/else, can have unlimited control flow possibilities. You can handle those options using nextControlFlow():

MethodSpec main = MethodSpec.methodBuilder("main")
    .addStatement("long now = $T.currentTimeMillis()", System.class)
    .beginControlFlow("if ($T.currentTimeMillis() < now)", System.class)
    .addStatement("$T.out.println($S)", System.class, "Time travelling, woo hoo!")
    .nextControlFlow("else if ($T.currentTimeMillis() == now)", System.class)
    .addStatement("$T.out.println($S)", System.class, "Time stood still!")
    .nextControlFlow("else")
    .addStatement("$T.out.println($S)", System.class, "Ok, time still moving forward")
    .endControlFlow()
    .build();

Which generates:

void main() {
  long now = System.currentTimeMillis();
  if (System.currentTimeMillis() < now)  {
    System.out.println("Time travelling, woo hoo!");
  } else if (System.currentTimeMillis() == now) {
    System.out.println("Time stood still!");
  } else {
    System.out.println("Ok, time still moving forward");
  }
}

Catching exceptions using try/catch is also a use case for nextControlFlow():

MethodSpec main = MethodSpec.methodBuilder("main")
    .beginControlFlow("try")
    .addStatement("throw new Exception($S)", "Failed")
    .nextControlFlow("catch ($T e)", Exception.class)
    .addStatement("throw new $T(e)", RuntimeException.class)
    .endControlFlow()
    .build();

Which produces:

void main() {
  try {
    throw new Exception("Failed");
  } catch (Exception e) {
    throw new RuntimeException(e);
  }
}

$L for Literals

The string-concatenation in calls to beginControlFlow() and addStatement is distracting. Too many operators. To address this, JavaPoet offers a syntax inspired-by but incompatible-with String.format(). It accepts $L to emit a literal value in the output. This works just like Formatter's %s:

private MethodSpec computeRange(String name, int from, int to, String op) {
  return MethodSpec.methodBuilder(name)
      .returns(int.class)
      .addStatement("int result = 0")
      .beginControlFlow("for (int i = $L; i < $L; i++)", from, to)
      .addStatement("result = result $L i", op)
      .endControlFlow()
      .addStatement("return result")
      .build();
}

Literals are emitted directly to the output code with no escaping. Arguments for literals may be strings, primitives, and a few JavaPoet types described below.

$S for Strings

When emitting code that includes string literals, we can use $S to emit a string, complete with wrapping quotation marks and escaping. Here's a program that emits 3 methods, each of which returns its own name:

public static void main(String[] args) throws Exception {
  TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
      .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
      .addMethod(whatsMyName("slimShady"))
      .addMethod(whatsMyName("eminem"))
      .addMethod(whatsMyName("marshallMathers"))
      .build();

  JavaFile javaFile = JavaFile.builder("com.example.helloworld", helloWorld)
      .build();

  javaFile.writeTo(System.out);
}

private static MethodSpec whatsMyName(String name) {
  return MethodSpec.methodBuilder(name)
      .returns(String.class)
      .addStatement("return $S", name)
      .build();
}

In this case, using $S gives us quotation marks:

public final class HelloWorld {
  String slimShady() {
    return "slimShady";
  }

  String eminem() {
    return "eminem";
  }

  String marshallMathers() {
    return "marshallMathers";
  }
}

$T for Types

We Java programmers love our types: they make our code easier to understand. And JavaPoet is on board. It has rich built-in support for types, including automatic generation of import statements. Just use $T to reference types:

MethodSpec today = MethodSpec.methodBuilder("today")
    .returns(Date.class)
    .addStatement("return new $T()", Date.class)
    .build();

TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
    .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
    .addMethod(today)
    .build();

JavaFile javaFile = JavaFile.builder("com.example.helloworld", helloWorld)
    .build();

javaFile.writeTo(System.out);

That generates the following .java file, complete with the necessary import:

package com.example.helloworld;

import java.util.Date;

public final class HelloWorld {
  Date today() {
    return new Date();
  }
}

We passed Date.class to reference a class that just-so-happens to be available when we're generating code. This doesn't need to be the case. Here's a similar example, but this one references a class that doesn't exist (yet):

ClassName hoverboard = ClassName.get("com.mattel", "Hoverboard");

MethodSpec today = MethodSpec.methodBuilder("tomorrow")
    .returns(hoverboard)
    .addStatement("return new $T()", hoverboard)
    .build();

And that not-yet-existent class is imported as well:

package com.example.helloworld;

import com.mattel.Hoverboard;

public final class HelloWorld {
  Hoverboard tomorrow() {
    return new Hoverboard();
  }
}

The ClassName type is very important, and you'll need it frequently when you're using JavaPoet. It can identify any declared class. Declared types are just the beginning of Java's rich type system: we also have arrays, parameterized types, wildcard types, and type variables. JavaPoet has classes for building each of these:

ClassName hoverboard = ClassName.get("com.mattel", "Hoverboard");
ClassName list = ClassName.get("java.util", "List");
ClassName arrayList = ClassName.get("java.util", "ArrayList");
TypeName listOfHoverboards = ParameterizedTypeName.get(list, hoverboard);

MethodSpec beyond = MethodSpec.methodBuilder("beyond")
    .returns(listOfHoverboards)
    .addStatement("$T result = new $T<>()", listOfHoverboards, arrayList)
    .addStatement("result.add(new $T())", hoverboard)
    .addStatement("result.add(new $T())", hoverboard)
    .addStatement("result.add(new $T())", hoverboard)
    .addStatement("return result")
    .build();

JavaPoet will decompose each type and import its components where possible.

package com.example.helloworld;

import com.mattel.Hoverboard;
import java.util.ArrayList;
import java.util.List;

public final class HelloWorld {
  List<Hoverboard> beyond() {
    List<Hoverboard> result = new ArrayList<>();
    result.add(new Hoverboard());
    result.add(new Hoverboard());
    result.add(new Hoverboard());
    return result;
  }
}

Import static

JavaPoet supports import static. It does it via explicitly collecting type member names. Let's enhance the previous example with some static sugar:

...
ClassName namedBoards = ClassName.get("com.mattel", "Hoverboard", "Boards");

MethodSpec beyond = MethodSpec.methodBuilder("beyond")
    .returns(listOfHoverboards)
    .addStatement("$T result = new $T<>()", listOfHoverboards, arrayList)
    .addStatement("result.add($T.createNimbus(2000))", hoverboard)
    .addStatement("result.add($T.createNimbus(\"2001\"))", hoverboard)
    .addStatement("result.add($T.createNimbus($T.THUNDERBOLT))", hoverboard, namedBoards)
    .addStatement("$T.sort(result)", Collections.class)
    .addStatement("return result.isEmpty() ? $T.emptyList() : result", Collections.class)
    .build();

TypeSpec hello = TypeSpec.classBuilder("HelloWorld")
    .addMethod(beyond)
    .build();

JavaFile.builder("com.example.helloworld", hello)
    .addStaticImport(hoverboard, "createNimbus")
    .addStaticImport(namedBoards, "*")
    .addStaticImport(Collections.class, "*")
    .build();

JavaPoet will first add your import static block to the file as configured, match and mangle all calls accordingly and also import all other types as needed.

package com.example.helloworld;

import static com.mattel.Hoverboard.Boards.*;
import static com.mattel.Hoverboard.createNimbus;
import static java.util.Collections.*;

import com.mattel.Hoverboard;
import java.util.ArrayList;
import java.util.List;

class HelloWorld {
  List<Hoverboard> beyond() {
    List<Hoverboard> result = new ArrayList<>();
    result.add(createNimbus(2000));
    result.add(createNimbus("2001"));
    result.add(createNimbus(THUNDERBOLT));
    sort(result);
    return result.isEmpty() ? emptyList() : result;
  }
}

$N for Names

Generated code is often self-referential. Use $N to refer to another generated declaration by its name. Here's a method that calls another:

public String byteToHex(int b) {
  char[] result = new char[2];
  result[0] = hexDigit((b >>> 4) & 0xf);
  result[1] = hexDigit(b & 0xf);
  return new String(result);
}

public char hexDigit(int i) {
  return (char) (i < 10 ? i + '0' : i - 10 + 'a');
}

When generating the code above, we pass the hexDigit() method as an argument to the byteToHex() method using $N:

MethodSpec hexDigit = MethodSpec.methodBuilder("hexDigit")
    .addParameter(int.class, "i")
    .returns(char.class)
    .addStatement("return (char) (i < 10 ? i + '0' : i - 10 + 'a')")
    .build();

MethodSpec byteToHex = MethodSpec.methodBuilder("byteToHex")
    .addParameter(int.class, "b")
    .returns(String.class)
    .addStatement("char[] result = new char[2]")
    .addStatement("result[0] = $N((b >>> 4) & 0xf)", hexDigit)
    .addStatement("result[1] = $N(b & 0xf)", hexDigit)
    .addStatement("return new String(result)")
    .build();

Code block format strings

Code blocks may specify the values for their placeholders in a few ways. Only one style may be used for each operation on a code block.

Relative Arguments

Pass an argument value for each placeholder in the format string to CodeBlock.add(). In each example, we generate code to say "I ate 3 tacos"

CodeBlock.builder().add("I ate $L $L", 3, "tacos")

Positional Arguments

Place an integer index (1-based) before the placeholder in the format string to specify which argument to use.

CodeBlock.builder().add("I ate $2L $1L", "tacos", 3)

Named Arguments

Use the syntax $argumentName:X where X is the format character and call CodeBlock.addNamed() with a map containing all argument keys in the format string. Argument names use characters in a-z, A-Z, 0-9, and _, and must start with a lowercase character.

Map<String, Object> map = new LinkedHashMap<>();
map.put("food", "tacos");
map.put("count", 3);
CodeBlock.builder().addNamed("I ate $count:L $food:L", map)

Methods

All of the above methods have a code body. Use Modifiers.ABSTRACT to get a method without any body. This is only legal if the enclosing class is either abstract or an interface.

MethodSpec flux = MethodSpec.methodBuilder("flux")
    .addModifiers(Modifier.ABSTRACT, Modifier.PROTECTED)
    .build();

TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
    .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
    .addMethod(flux)
    .build();

Which generates this:

public abstract class HelloWorld {
  protected abstract void flux();
}

The other modifiers work where permitted. Note that when specifying modifiers, JavaPoet uses javax.lang.model.element.Modifier, a class that is not available on Android. This limitation applies to code-generating-code only; the output code runs everywhere: JVMs, Android, and GWT.

Methods also have parameters, exceptions, varargs, Javadoc, annotations, type variables, and a return type. All of these are configured with MethodSpec.Builder.

Constructors

MethodSpec is a slight misnomer; it can also be used for constructors:

MethodSpec flux = MethodSpec.constructorBuilder()
    .addModifiers(Modifier.PUBLIC)
    .addParameter(String.class, "greeting")
    .addStatement("this.$N = $N", "greeting", "greeting")
    .build();

TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
    .addModifiers(Modifier.PUBLIC)
    .addField(String.class, "greeting", Modifier.PRIVATE, Modifier.FINAL)
    .addMethod(flux)
    .build();

Which generates this:

public class HelloWorld {
  private final String greeting;

  public HelloWorld(String greeting) {
    this.greeting = greeting;
  }
}

For the most part, constructors work just like methods. When emitting code, JavaPoet will place constructors before methods in the output file.

Parameters

Declare parameters on methods and constructors with either ParameterSpec.builder() or MethodSpec's convenient addParameter() API:

ParameterSpec android = ParameterSpec.builder(String.class, "android")
    .addModifiers(Modifier.FINAL)
    .build();

MethodSpec welcomeOverlords = MethodSpec.methodBuilder("welcomeOverlords")
    .addParameter(android)
    .addParameter(String.class, "robot", Modifier.FINAL)
    .build();

Though the code above to generate android and robot parameters is different, the output is the same:

void welcomeOverlords(final String android, final String robot) {
}

The extended Builder form is necessary when the parameter has annotations (such as @Nullable).

Fields

Like parameters, fields can be created either with builders or by using convenient helper methods:

FieldSpec android = FieldSpec.builder(String.class, "android")
    .addModifiers(Modifier.PRIVATE, Modifier.FINAL)
    .build();

TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
    .addModifiers(Modifier.PUBLIC)
    .addField(android)
    .addField(String.class, "robot", Modifier.PRIVATE, Modifier.FINAL)
    .build();

Which generates:

public class HelloWorld {
  private final String android;

  private final String robot;
}

The extended Builder form is necessary when a field has Javadoc, annotations, or a field initializer. Field initializers use the same String.format()-like syntax as the code blocks above:

FieldSpec android = FieldSpec.builder(String.class, "android")
    .addModifiers(Modifier.PRIVATE, Modifier.FINAL)
    .initializer("$S + $L", "Lollipop v.", 5.0d)
    .build();

Which generates:

private final String android = "Lollipop v." + 5.0;

Interfaces

JavaPoet has no trouble with interfaces. Note that interface methods must always be PUBLIC ABSTRACT and interface fields must always be PUBLIC STATIC FINAL. These modifiers are necessary when defining the interface:

TypeSpec helloWorld = TypeSpec.interfaceBuilder("HelloWorld")
    .addModifiers(Modifier.PUBLIC)
    .addField(FieldSpec.builder(String.class, "ONLY_THING_THAT_IS_CONSTANT")
        .addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
        .initializer("$S", "change")
        .build())
    .addMethod(MethodSpec.methodBuilder("beep")
        .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
        .build())
    .build();

But these modifiers are omitted when the code is generated. These are the defaults so we don't need to include them for javac's benefit!

public interface HelloWorld {
  String ONLY_THING_THAT_IS_CONSTANT = "change";

  void beep();
}

Enums

Use enumBuilder to create the enum type, and addEnumConstant() for each value:

TypeSpec helloWorld = TypeSpec.enumBuilder("Roshambo")
    .addModifiers(Modifier.PUBLIC)
    .addEnumConstant("ROCK")
    .addEnumConstant("SCISSORS")
    .addEnumConstant("PAPER")
    .build();

To generate this:

public enum Roshambo {
  ROCK,

  SCISSORS,

  PAPER
}

Fancy enums are supported, where the enum values override methods or call a superclass constructor. Here's a comprehensive example:

TypeSpec helloWorld = TypeSpec.enumBuilder("Roshambo")
    .addModifiers(Modifier.PUBLIC)
    .addEnumConstant("ROCK", TypeSpec.anonymousClassBuilder("$S", "fist")
        .addMethod(MethodSpec.methodBuilder("toString")
            .addAnnotation(Override.class)
            .addModifiers(Modifier.PUBLIC)
            .addStatement("return $S", "avalanche!")
            .returns(String.class)
            .build())
        .build())
    .addEnumConstant("SCISSORS", TypeSpec.anonymousClassBuilder("$S", "peace")
        .build())
    .addEnumConstant("PAPER", TypeSpec.anonymousClassBuilder("$S", "flat")
        .build())
    .addField(String.class, "handsign", Modifier.PRIVATE, Modifier.FINAL)
    .addMethod(MethodSpec.constructorBuilder()
        .addParameter(String.class, "handsign")
        .addStatement("this.$N = $N", "handsign", "handsign")
        .build())
    .build();

Which generates this:

public enum Roshambo {
  ROCK("fist") {
    @Override
    public String toString() {
      return "avalanche!";
    }
  },

  SCISSORS("peace"),

  PAPER("flat");

  private final String handsign;

  Roshambo(String handsign) {
    this.handsign = handsign;
  }
}

Anonymous Inner Classes

In the enum code, we used TypeSpec.anonymousInnerClass(). Anonymous inner classes can also be used in code blocks. They are values that can be referenced with $L:

TypeSpec comparator = TypeSpec.anonymousClassBuilder("")
    .addSuperinterface(ParameterizedTypeName.get(Comparator.class, String.class))
    .addMethod(MethodSpec.methodBuilder("compare")
        .addAnnotation(Override.class)
        .addModifiers(Modifier.PUBLIC)
        .addParameter(String.class, "a")
        .addParameter(String.class, "b")
        .returns(int.class)
        .addStatement("return $N.length() - $N.length()", "a", "b")
        .build())
    .build();

TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
    .addMethod(MethodSpec.methodBuilder("sortByLength")
        .addParameter(ParameterizedTypeName.get(List.class, String.class), "strings")
        .addStatement("$T.sort($N, $L)", Collections.class, "strings", comparator)
        .build())
    .build();

This generates a method that contains a class that contains a method:

void sortByLength(List<String> strings) {
  Collections.sort(strings, new Comparator<String>() {
    @Override
    public int compare(String a, String b) {
      return a.length() - b.length();
    }
  });
}

One particularly tricky part of defining anonymous inner classes is the arguments to the superclass constructor. In the above code we're passing the empty string for no arguments: TypeSpec.anonymousClassBuilder(""). To pass different parameters use JavaPoet's code block syntax with commas to separate arguments.

Annotations

Simple annotations are easy:

MethodSpec toString = MethodSpec.methodBuilder("toString")
    .addAnnotation(Override.class)
    .returns(String.class)
    .addModifiers(Modifier.PUBLIC)
    .addStatement("return $S", "Hoverboard")
    .build();

Which generates this method with an @Override annotation:

  @Override
  public String toString() {
    return "Hoverboard";
  }

Use AnnotationSpec.builder() to set properties on annotations:

MethodSpec logRecord = MethodSpec.methodBuilder("recordEvent")
    .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
    .addAnnotation(AnnotationSpec.builder(Headers.class)
        .addMember("accept", "$S", "application/json; charset=utf-8")
        .addMember("userAgent", "$S", "Square Cash")
        .build())
    .addParameter(LogRecord.class, "logRecord")
    .returns(LogReceipt.class)
    .build();

Which generates this annotation with accept and userAgent properties:

@Headers(
    accept = "application/json; charset=utf-8",
    userAgent = "Square Cash"
)
LogReceipt recordEvent(LogRecord logRecord);

When you get fancy, annotation values can be annotations themselves. Use $L for embedded annotations:

MethodSpec logRecord = MethodSpec.methodBuilder("recordEvent")
    .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
    .addAnnotation(AnnotationSpec.builder(HeaderList.class)
        .addMember("value", "$L", AnnotationSpec.builder(Header.class)
            .addMember("name", "$S", "Accept")
            .addMember("value", "$S", "application/json; charset=utf-8")
            .build())
        .addMember("value", "$L", AnnotationSpec.builder(Header.class)
            .addMember("name", "$S", "User-Agent")
            .addMember("value", "$S", "Square Cash")
            .build())
        .build())
    .addParameter(LogRecord.class, "logRecord")
    .returns(LogReceipt.class)
    .build();

Which generates this:

@HeaderList({
    @Header(name = "Accept", value = "application/json; charset=utf-8"),
    @Header(name = "User-Agent", value = "Square Cash")
})
LogReceipt recordEvent(LogRecord logRecord);

Note that you can call addMember() multiple times with the same property name to populate a list of values for that property.

Javadoc

Fields, methods and types can be documented with Javadoc:

MethodSpec dismiss = MethodSpec.methodBuilder("dismiss")
    .addJavadoc("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")
    .addJavadoc("\n")
    .addJavadoc("<p>Use {@link #delete($T)} to delete the entire\n"
        + "conversation for all participants.\n", Conversation.class)
    .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
    .addParameter(Message.class, "message")
    .build();

Which generates this:

  /**
   * Hides {@code message} from the caller's history. Other
   * participants in the conversation will continue to see the
   * message in their own history unless they also delete it.
   *
   * <p>Use {@link #delete(Conversation)} to delete the entire
   * conversation for all participants.
   */
  void dismiss(Message message);

Use $T when referencing types in Javadoc to get automatic imports.

Download

Download the latest .jar or depend via Maven:

<dependency>
  <groupId>com.squareup</groupId>
  <artifactId>javapoet</artifactId>
  <version>1.13.0</version>
</dependency>

or Gradle:

compile 'com.squareup:javapoet:1.13.0'

Snapshots of the development version are available in Sonatype's snapshots repository.

License

Copyright 2015 Square, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

JavaWriter

JavaPoet is the successor to JavaWriter. New projects should prefer JavaPoet because it has a stronger code model: it understands types and can manage imports automatically. JavaPoet is also better suited to composition: rather than streaming the contents of a .java file top-to-bottom in a single pass, a file can be assembled as a tree of declarations.

JavaWriter continues to be available in GitHub and Maven Central.

Comments
  • AnnotationSpec.get and MethodSpec.overriding

    AnnotationSpec.get and MethodSpec.overriding

    Added static get method to AnnotationSpec using an AnnotationMirror as source.

    Next, I implemented some of the TODOs in MethodSpec.overriding - and changed the signature to include an ExecutableType. That allows the actual generic type parameters retrieval for the return type and the signature. See the interface extending parameterized interfaces test case: ExtendsOthers in MethodSpecTest.

    PS: This time, checkstyle and unit tests are green: https://travis-ci.org/sormuras/javapoet

    opened by sormuras 25
  • Type annotations on qualified names

    Type annotations on qualified names

    Type annotations on qualified names have to be applied to the simple name of the type. JLS §9.7.4 says:

    It is a compile-time error if an annotation of type T applies to a type (or any part of a type) in a type context, and T is applicable in type contexts, and the annotation is not admissible.

    For example, assume an annotation type TA which is meta-annotated with just @Target(ElementType.TYPE_USE). The terms @TA java.lang.Object and java.@TA lang.Object are illegal because the simple name to which @TA is closest is classified as a package name. On the other hand, java.lang.@TA Object is legal.

    Incorrect:

    @Target(ElementType.TYPE_USE)
    @interface Anno {}
    
    class Test {
      @Anno java.util.Map.Entry e;
    }
    
    error: scoping construct cannot be annotated with type-use annotation: @Anno
    

    Correct:

    java.util.Map.@Anno Entry e;
    

    JavaPoet doesn't get this right.

    Failing test case:

    diff --git a/src/test/java/com/squareup/javapoet/AnnotatedTypeNameTest.java b/src/test/java/com/squareup/javapoet/AnnotatedTypeNameTest.java
    index 35b2b1f..e420d85 100644
    --- a/src/test/java/com/squareup/javapoet/AnnotatedTypeNameTest.java
    +++ b/src/test/java/com/squareup/javapoet/AnnotatedTypeNameTest.java
    @@ -20,16 +20,24 @@ import static org.junit.Assert.assertFalse;
     import static org.junit.Assert.assertNotEquals;
     import static org.junit.Assert.assertTrue;
    
    +import java.lang.annotation.ElementType;
    +import java.lang.annotation.Target;
     import java.util.List;
    +import java.util.Map;
     import org.junit.Test;
    
     public class AnnotatedTypeNameTest {
    
       private final static String NN = NeverNull.class.getCanonicalName();
       private final AnnotationSpec NEVER_NULL = AnnotationSpec.builder(NeverNull.class).build();
    +  private final AnnotationSpec TYPE_USE_ANNOTATION =
    +      AnnotationSpec.builder(TypeUseAnnotation.class).build();
    
       public @interface NeverNull {}
    
    +  @Target(ElementType.TYPE_USE)
    +  public @interface TypeUseAnnotation {}
    +
       @Test(expected=NullPointerException.class) public void nullAnnotationArray() {
         TypeName.BOOLEAN.annotated((AnnotationSpec[]) null);
       }
    @@ -102,6 +110,14 @@ public class AnnotatedTypeNameTest {
         annotatedEquivalence(WildcardTypeName.get(Object.class));
       }
    
    +  @Test public void annotatedNestedType() {
    +    String expected =
    +        "java.util.Map.@com.squareup.javapoet.AnnotatedTypeNameTest.TypeUseAnnotation Entry";
    +    TypeName type = TypeName.get(Map.Entry.class).annotated(TYPE_USE_ANNOTATION);
    +    String actual = type.toString();
    +    assertEquals(expected, actual);
    +  }
    +
       private void annotatedEquivalence(TypeName type) {
         assertFalse(type.isAnnotated());
         assertEquals(type, type);
    
    Expected :java.util.Map.@com.squareup.javapoet.AnnotatedTypeNameTest.TypeUseAnnotation Entry
    Actual   :@com.squareup.javapoet.AnnotatedTypeNameTest.TypeUseAnnotation java.util.Map.Entry
    
    opened by cushon 23
  • In line imports for fields

    In line imports for fields

    I am trying to generate a file and sometimes i need to import another generated class. So the import has to be in line. private com.example.GeneratedClass generatedClass;

    But i was not able to achieve this. I had to import them manually.

    invalid 
    opened by Zeyad-37 22
  • Type annotations

    Type annotations

    This would be really easy if TypeName was an abstract class...

    Examples:

    @NonNull List<String>
    List<@NonNull String>
    new @Thing Foo();
    new Foo.@Thing Bar();
    foo.new @Thing Bar();
    <? super @NonNull String>
    <T extends @Thing Foo>
    
    enhancement 
    opened by JakeWharton 22
  • Option to manually add an import

    Option to manually add an import

    Hi, I am aware that JavaPoet is automatically managing imports, but I would appreciate possibility to manually add non-static import.

    The need occurs when I copy method implementation from an existing class to a class I build with JavaPoet. I don't really know what the method implementation looks like, nor I care. But the implementation may be depending on an import statement, which JavaPoet is not and can't be aware of.

    Note that parsing method implementation is heroic task, which I want to avoid. Thanks

    poor man's workaround

    This one is for field initializers, but same applies to code in methods.

    initializerString = initializerString.replaceAll("HashSet", "java.util.HashSet"); // etc.
    
    opened by vovcacik 21
  • Can't add modifier to any spec in Android Studio

    Can't add modifier to any spec in Android Studio

    Calling addModifiers on TypeSpec results in can't resolve method error. After looking at source code, I have found that javax.lang.model.element.Modifier is not imported in source files. I am attaching a also attaching a snapshot, please have a look. capture

    opened by allaudin 19
  • adding configurable indent

    adding configurable indent

    Hi,

    I have added configurable indent. It solves issue #106 . Indent can be configured in JavaPoet class (old JavaWriter class). Exemplary usage of the configurable indent is presented in the following code snippet:

    new JavaPoet(new Indent().level(4));
    

    In addition, I've added appropriate Unit Tests verifying behavior of the library with new functionality. I wanted to make code clean and as abstract as possible.

    I hope it would be useful for you.

    Regards, Piotr

    opened by pwittchen 16
  • Version 3.0 Working Spec

    Version 3.0 Working Spec

    This issue will serve as a working space for what a potential version 3.0 would look like with a new, more dynamic, and more powerful API.

    High-Level Goals

    • The ability to defer type compression (imports) until emission.
    • Distinct code blocks as objects for composition.
    • And more, probably...

    Deferred Type Compression

    Currently, type compression via imports requires knowledge of all types up before the body of the file. In practice, this usually requires an awkward two-pass approach where you determine the imports based on a pass of dynamic contents and then emit the body based on a second pass.

    The goal of this is to always emit fully-qualified types from the API and rely on a post-compression phase for emitting imports.

    There are multiple ways to approach this. A non-exhaustive list:

    • Type location-aware parsing of code statements combined with type parameters.
    • Method which wraps a type in a token that can later be replaced.
    • Code blocks which are aware of which types they contain. (see below)

    Code Block Objects

    Objects which represents pieces of code lend themselves naturally to writing emission code in Java. The wins should hopefully be fairly obvious.

    There is a potential for API explosion here to cover the diversity of the Java language. A potential also exists for adding an unacceptable amount of boilerplate to the API.

    opened by JakeWharton 16
  • Fix bug when using javapoet with Eclipse compiler

    Fix bug when using javapoet with Eclipse compiler

    For the following code:

    public interface Interface1 {}
    public interface Interface 2 {}
    public T myMethod(T input) {}
    

    a code generator (javax.annotation.processing.Processor) in eclipse will have a TypeVariable for the return type T instead of a DeclaredType.

    This results in a stack overflow exception, because the return value of Collections.singletonList(upperBound) ends up returning a list containing, in essence, the input parameter.

    opened by marcosb 15
  • Add support for annotated method parameters.

    Add support for annotated method parameters.

    Which of the following API design is better on interface and abstract methods that will support annotated parameters?

    javaWriter.beginMethodSignature(returnType, methodName, modifiers);
    javaWriter.emitAnnotation(annotationType);
    javaWriter.emitParam(paramType, paramName);
    javaWriter.endMethodSignature();
    

    or

    javaWriter.beginMethodSignature(returnType, methodName, modifiers);
    javaWriter.emitAnnotation(annotationType);
    javaWriter.emitParam(paramType, paramName);
    javaWriter.endMethodSignature();
    javaWriter.endMethod(); // <== Regardless of the type definition or modifier??
    
    opened by ragunathjawahar 15
  • Added support for interface method declarations.

    Added support for interface method declarations.

    Lack of support for interface method declarations. This pull request enables support.

    Method added JavaWriter.declareMethod() with and without throwables + unit tests.

    public interface Foo {
      String getFooMessage();
    }
    
    opened by ragunathjawahar 14
  • Bump mockito-core from 4.5.1 to 4.9.0

    Bump mockito-core from 4.5.1 to 4.9.0

    Bumps mockito-core from 4.5.1 to 4.9.0.

    Release notes

    Sourced from mockito-core's releases.

    v4.9.0

    Changelog generated by Shipkit Changelog Gradle Plugin

    4.9.0

    v4.8.1

    Changelog generated by Shipkit Changelog Gradle Plugin

    4.8.1

    v4.8.0

    Changelog generated by Shipkit Changelog Gradle Plugin

    4.8.0

    v4.7.0

    Changelog generated by Shipkit Changelog Gradle Plugin

    4.7.0

    • 2022-08-13 - 33 commit(s) by 198812345678, Andy Coates, Chen Ni, Marius Lichtblau, Nikita Koselev. Developer Advocate, Open Source Ally, Rafael Winterhalter, dependabot[bot], dstango, fishautumn, heqiang
    • Bump com.diffplug.spotless from 6.9.0 to 6.9.1 [(#2725)](mockito/mockito#2725)
    • Bump versions.bytebuddy from 1.12.12 to 1.12.13 [(#2719)](mockito/mockito#2719)

    ... (truncated)

    Commits
    • 0052e2f Avoid clearing stale weak entries from critical code segments (#2780)
    • 47045cb Upgrade objenesis 3.2 -> 3.3 (#2784)
    • eb85518 Update gradle to 7.5.1 (#2776)
    • fcb4cf7 Bump gradle/wrapper-validation-action from 1.0.4 to 1.0.5 (#2775)
    • f512a76 Bump gradle-errorprone-plugin from 2.0.2 to 3.0.1 (#2770)
    • fe7dca2 Bump junit-platform-launcher from 1.9.0 to 1.9.1 (#2768)
    • 4d14d97 Bump versions.junitJupiter from 5.9.0 to 5.9.1 (#2758)
    • 3507ce3 Use downloaded package-list file from Oracle for JavaDoc generation (#2766)
    • 0a9aa26 Bump groovy from 3.0.12 to 3.0.13 (#2756)
    • ee3679b Bump com.diffplug.spotless from 6.10.0 to 6.11.0 (#2753)
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    dependencies java 
    opened by dependabot[bot] 0
  • `ParameterizedTypeName#annotated` would add the annotations repeatedly.

    `ParameterizedTypeName#annotated` would add the annotations repeatedly.

    When we first used the #annotated( A, B, C ) method, it appended the annotations both to the ParameterizedTypeName.this.rawType and TypeName.this.annotations, while if we use the #annotated() method again, the annotations A, B, C would appended to rawType repeatedly.

    image image

    opened by zhengxiaoyao0716 0
  • Bump checkstyle from 8.18 to 10.3.4

    Bump checkstyle from 8.18 to 10.3.4

    Bumps checkstyle from 8.18 to 10.3.4.

    Release notes

    Sourced from checkstyle's releases.

    checkstyle-10.3.4

    https://checkstyle.org/releasenotes.html#Release_10.3.4

    checkstyle-10.3.3

    https://checkstyle.org/releasenotes.html#Release_10.3.3

    checkstyle-10.3.2

    https://checkstyle.org/releasenotes.html#Release_10.3.2

    Bug fixes:

    #11736 - MissingJavadocType: Support qualified annotation names #11655 - Update google_checks.xml to have the SuppressionCommentFilter and SuppressWarningsHolder modules in the config by default (and by extension, SuppressWarningsFilter)

    ... (truncated)

    Commits
    • 6de3b9f [maven-release-plugin] prepare release checkstyle-10.3.4
    • a4497de doc: release notes 10.3.4
    • 32e8d37 Issue #12145: corrected tokens so all are required
    • 96e3e05 dependency: bump pitest-accelerator-junit5 from 1.0.1 to 1.0.2
    • 37842d2 Issue #3955: corrected tokens so all are required
    • 38ee347 minor: remove unnecessary checkstyle versions to diff.groovy
    • 318770d dependency: bump slf4j-simple from 2.0.1 to 2.0.2
    • 1194536 dependency: bump junit.version from 5.9.0 to 5.9.1
    • 5a56c16 Issue #12132: Fix ArrayIndexOutOfBoundsException in pitest-survival-check-xml...
    • 701bd65 Issue #12210: Add method to ignore unstable checker framework violations
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    dependencies java 
    opened by dependabot[bot] 1
  • New release 1.14.0?

    New release 1.14.0?

    I'm hoping to use a version of JavaPoet with this performance fix: https://github.com/square/javapoet/pull/828

    That PR merged in March 2021. The last release, 1.13.0, was in June 2020.

    Is anyone in a position to cut a new release of the library?

    opened by AlexLandau 2
  • Bump maven-checkstyle-plugin from 3.1.2 to 3.2.0

    Bump maven-checkstyle-plugin from 3.1.2 to 3.2.0

    Bumps maven-checkstyle-plugin from 3.1.2 to 3.2.0.

    Commits
    • 1aaf7cb [maven-release-plugin] prepare release maven-checkstyle-plugin-3.2.0
    • 627fa4f [MCHECKSTYLE-417] Upgrade Maven Reporting API to 3.1.1/Maven Reporting Impl t...
    • cbf3751 [MCHECKSTYLE-418] Deprecate RSS feature and disable by default
    • 549bf3d [MCHECKSTYLE-419] Upgrade Parent to 37 and cleanup
    • 171827b Bump animal-sniffer-maven-plugin from 1.21 to 1.22
    • a58c637 Bump extra-enforcer-rules from 1.5.1 to 1.6.1
    • c2587c4 Bump maven-enforcer-plugin from 3.0.0 to 3.1.0
    • d67f2ff [MCHECKSTYLE-414] - documentation: property expansion example does not parse
    • d88c261 Bump plexus-utils from 3.4.1 to 3.4.2
    • 4484b3b Bump maven-reporting-impl from 3.0.0 to 3.1.0
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    dependencies java 
    opened by dependabot[bot] 0
Owner
Square
Square
Annotation Processor for generating Parcelable code

ParcelablePlease An AnnotationProcessor for generating Android Parcelable boilerplate code. See this blog entry for comparison with other parcel libra

Hannes Dorfmann 260 Mar 31, 2022
Generate MVVM-UseCase-Api-DI feature packages with 1 click

Android MVVM Generator Pre-requisites Project assumes that you use Hilt, Retrofit, Kotlin, Flows, Jetpack ViewModel and MVVM with UseCase layer. Impor

Talha Hasan Zia 16 Dec 10, 2022
A Java Code Generator for Pojo Builders

PojoBuilder - A Code Generator for Pojo Builders Author: Michael Karneim Project Homepage: http://github.com/mkarneim/pojobuilder About The PojoBuilde

Michael Karneim 330 Dec 11, 2022
Kotlin and Java API for generating .swift source files.

SwiftPoet SwiftPoet is a Kotlin and Java API for generating .swift source files. Source file generation can be useful when doing things such as annota

Outfox 232 Jan 2, 2023
DuGuang 1k Dec 14, 2022
Gradle plugin which allows to use typed DSL for generating kubernetes/openshift YAML files

gr8s Gradle plugin which allows using typed DSL for generating kubernetes/openshift YAML files. Based on kuberig Usage import io.github.guai.gr8s.Gene

null 0 Jan 3, 2022
An experimental UI toolkit for generating PowerPoint presentation files using Compose

ComposePPT An experimental UI toolkit for generating PowerPoint presentation files(.pptx) using Compose. Inspired by Glance and Mosaic. Why? This proj

Fatih Giriş 252 Dec 28, 2022
Pure Java code generation tool for generating a fully functional ContentProvider for Android.

RoboCoP RoboCoP is a Java library that can generate a fully-functional ContentProvider from a simple JSON schema file. Get the latest version from our

Rain 246 Dec 29, 2022
This directory contains the model files (protos) for the Bar ServiceThis directory contains the model files (protos) for the Bar Service

This directory contains the model files (protos) for the Bar ServiceThis directory contains the model files (protos) for the Bar Service

Logesh Dinakaran 0 Nov 22, 2021
ICSx⁵ is an Android app to subscribe to remote or local iCalendar files (like time tables of your school/university or event files of your sports team).

ICSx⁵ ICSx⁵ is an Android app to subscribe to remote Webcal feeds / iCalendar files (like time tables of your school/university or event files of your

bitfire web engineering 60 Dec 28, 2022
An E-Commerce android App whose frontend is implemented using Kotlin & XML files and backend/database is implemented using My SQL & PHP files

An E-Commerce android App whose frontend is implemented using Kotlin & XML files and backend/database is implemented using My SQL & PHP files

null 4 Aug 25, 2022
A Java API to read, write and create MP4 files

Build status: Current central released version 1.x branch: Current central released version 2.x branch: Java MP4 Parser A Java API to read, write and

Sebastian Annies 2.6k Dec 30, 2022
A Java API to read, write and create MP4 files

Build status: Current central released version 1.x branch: Current central released version 2.x branch: Java MP4 Parser A Java API to read, write and

Sebastian Annies 2.4k Apr 2, 2021
Utility Android app for generating color palettes of images using the Palette library. Written in Kotlin.

Palette Helper is a simple utility app made to generate color palettes of images using Google's fantastic Palette library. It's mostly a for-fun pet p

Zac Sweers 154 Nov 18, 2022
Utility Android app for generating color palettes of images using the Palette library. Written in Kotlin.

Palette Helper is a simple utility app made to generate color palettes of images using Google's fantastic Palette library. It's mostly a for-fun pet p

Zac Sweers 154 Nov 18, 2022
Annotation Processor for generating Parcelable code

ParcelablePlease An AnnotationProcessor for generating Android Parcelable boilerplate code. See this blog entry for comparison with other parcel libra

Hannes Dorfmann 260 Mar 31, 2022
Intellij Idea, Android Studio plugin for generating Kotlin data classes from JSON. Helps to avoid writing boilerplate code for model classes. Supports annotations for Gson, Moshi, Jackson.

JSONToKotlinClass Intellij Idea, Android Studio plugin. Plugin generates Kotlin data classes from JSON text. It can find inner classes in nested JSON.

Vasily 139 Dec 21, 2022
Android library for auto generating SQL schema and Content provider

Android-AnnotatedSQL Android library for auto generating SQL schema and Content Provider by annotations. You will get a full-featured content provider

Gennadiy Dubina 161 Dec 3, 2022
Android Studio plug-in for generating ButterKnife injections from selected layout XML.

ButterKnifeZelezny Simple plug-in for Android Studio/IDEA that allows one-click creation of Butterknife view injections. How to install in Android Stu

Avast 3.4k Dec 14, 2022
A set of web-based tools for generating graphics and other assets that would eventually be in an Android application's res/ directory.

Android Asset Studio Open the Android Asset Studio See the older version if you're having trouble with the new version A web-based set of tools for ge

Roman Nurik 6.3k Dec 31, 2022