JavaPoet 使い方メモ

#JavaPoet とは
Java のソースコードを動的に生成するためのライブラリ。

#インストール
```groovy:build.gradle
    compile 'com.squareup:javapoet:1.1.0'
```

#Hello World
```java:
import java.io.IOException;

import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.TypeSpec;

public class Main {
    public static void main(String... args) throws IOException {
        TypeSpec typeSpec = TypeSpec.classBuilder("Hoge").build();
        
        JavaFile javaFile = JavaFile.builder("sample.javapoet", typeSpec).build();
        
        javaFile.writeTo(System.out);
    }
}
```

```java:生成されたコード
package sample.javapoet;

class Hoge {
}
```

- `TypeSpec#classBuilder()` を使って、クラス定義を生成する。
- `JavaFile#builder()` で、 `JavaFile` インスタンスを生成する。
- `JavaFile#writeTo()` を使って、コードを出力する。

#クラス定義いろいろ
##修飾子いろいろ
```java:
import java.io.IOException;

import javax.lang.model.element.Modifier;

import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.TypeSpec;

public class Main {
    public static void main(String... args) throws IOException {
        TypeSpec typeSpec = TypeSpec.classBuilder("Hoge")
                                    .addModifiers(Modifier.FINAL, Modifier.PUBLIC) // ★
                                    .build();
        
        JavaFile javaFile = JavaFile.builder("sample.javapoet", typeSpec).build();
        
        javaFile.writeTo(System.out);
    }
}
```

```java:生成されたコード
package sample.javapoet;

public final class Hoge {
}
```

- `addModifiers()` で、修飾子をいろいろ設定できる。

##親クラス・インターフェース
```java:
import java.io.IOException;
import java.io.Serializable;

import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.TypeSpec;

public class Main {
    public static void main(String... args) throws IOException {
        TypeSpec typeSpec = TypeSpec.classBuilder("Hoge")
                                    .addSuperinterface(Serializable.class) // ★
                                    .superclass(Exception.class) // ★
                                    .build();
        
        JavaFile javaFile = JavaFile.builder("sample.javapoet", typeSpec).build();
        
        javaFile.writeTo(System.out);
    }
}
```

```java:生成されたコード
package sample.javapoet;

import java.io.Serializable;
import java.lang.Exception;

class Hoge extends Exception implements Serializable {
}
```

##アノテーションをつける
```java:
import java.io.IOException;

import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.TypeSpec;

public class Main {
    public static void main(String... args) throws IOException {
        TypeSpec typeSpec = TypeSpec.classBuilder("Hoge")
                                    .addAnnotation(Deprecated.class) // ★
                                    .build();
        
        JavaFile javaFile = JavaFile.builder("sample.javapoet", typeSpec).build();
        
        javaFile.writeTo(System.out);
    }
}
```

```java:生成されたコード
package sample.javapoet;

import java.lang.Deprecated;

@Deprecated
class Hoge {
}
```

###アノテーションに引数を指定する
```java:
import java.io.IOException;

import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.TypeSpec;

public class Main {
    public static void main(String... args) throws IOException {
        AnnotationSpec annotationSpec = AnnotationSpec.builder(SuppressWarnings.class)
                                                      .addMember("value", "$S", "unchecked") // ★
                                                      .build();
        
        TypeSpec typeSpec = TypeSpec.classBuilder("Hoge")
                                    .addAnnotation(annotationSpec)
                                    .build();
        
        JavaFile javaFile = JavaFile.builder("sample.javapoet", typeSpec).build();
        
        javaFile.writeTo(System.out);
    }
}
```

```java:生成されたコード
package sample.javapoet;

import java.lang.SuppressWarnings;

@SuppressWarnings("unchecked")
class Hoge {
}
```

- `$S` は、 JavaPoet 独自の書式指定で、文字列リテラルを埋め込むことを表している（[詳細後述](#書式指定)）。

##Javadoc を付ける
```java:
import java.io.IOException;

import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.TypeSpec;

public class Main {
    public static void main(String... args) throws IOException {
        TypeSpec typeSpec = TypeSpec.classBuilder("Hoge")
                                    .addJavadoc("Generated by JavaPoet.\n") // ★
                                    .addJavadoc("@see https://github.com/square/javapoet\n") // ★
                                    .build();
        
        JavaFile javaFile = JavaFile.builder("sample.javapoet", typeSpec).build();
        
        javaFile.writeTo(System.out);
    }
}
```

```java:生成されたコード
package sample.javapoet;

/**
 * Generated by JavaPoet.
 * @see https://github.com/square/javapoet
 */
class Hoge {
}
```

##型引数を宣言する
```java:
import java.io.IOException;

import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeVariableName;

public class Main {
    public static void main(String... args) throws IOException {
        TypeVariableName typeVariable = TypeVariableName.get("T"); // ★
        
        TypeSpec typeSpec = TypeSpec.classBuilder("Hoge")
                                    .addTypeVariable(typeVariable) // ★
                                    .build();
        
        JavaFile javaFile = JavaFile.builder("sample.javapoet", typeSpec).build();
        
        javaFile.writeTo(System.out);
    }
}
```

```java:生成されたコード
package sample.javapoet;

class Hoge<T> {
}
```

###型引数の extends
```java:
import java.io.IOException;

import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeVariableName;

public class Main {
    public static void main(String... args) throws IOException {
        TypeVariableName typeVariable = TypeVariableName.get("T", Number.class); // ★
        
        TypeSpec typeSpec = TypeSpec.classBuilder("Hoge")
                                    .addTypeVariable(typeVariable)
                                    .build();
        
        JavaFile javaFile = JavaFile.builder("sample.javapoet", typeSpec).build();
        
        javaFile.writeTo(System.out);
    }
}
```

```java:生成されたコード
package sample.javapoet;

import java.lang.Number;

class Hoge<T extends Number> {
}
```

##フィールドの宣言
```java:
import java.io.IOException;

import javax.lang.model.element.Modifier;

import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.TypeSpec;

public class Main {
    public static void main(String... args) throws IOException {
        FieldSpec fieldSpec = FieldSpec.builder(String.class, "string", Modifier.PRIVATE) // ★
                                       .build();
        
        TypeSpec typeSpec = TypeSpec.classBuilder("Hoge")
                                    .addField(fieldSpec) // ★
                                    .build();
        
        JavaFile javaFile = JavaFile.builder("sample.javapoet", typeSpec).build();
        
        javaFile.writeTo(System.out);
    }
}
```

```java:生成されたコード
package sample.javapoet;

import java.lang.String;

class Hoge {
  private String string;
}
```

###初期化
```java:
import java.io.IOException;

import javax.lang.model.element.Modifier;

import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.TypeSpec;

public class Main {
    public static void main(String... args) throws IOException {
        FieldSpec fieldSpec = FieldSpec.builder(String.class, "string", Modifier.PRIVATE)
                                       .initializer("$S", "hoge") // ★
                                       .build();
        
        TypeSpec typeSpec = TypeSpec.classBuilder("Hoge")
                                    .addField(fieldSpec)
                                    .build();
        
        JavaFile javaFile = JavaFile.builder("sample.javapoet", typeSpec).build();
        
        javaFile.writeTo(System.out);
    }
}
```

```java:生成されたコード
package sample.javapoet;

import java.lang.String;

class Hoge {
  private String string = "hoge";
}
```

###型引数付きの変数宣言
```java:
import java.io.IOException;
import java.util.List;

import javax.lang.model.element.Modifier;

import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeSpec;

public class Main {
    public static void main(String... args) throws IOException {
        ParameterizedTypeName parameterizedTypeName = ParameterizedTypeName.get(List.class, String.class); // ★
        
        FieldSpec fieldSpec = FieldSpec.builder(parameterizedTypeName, "list", Modifier.PRIVATE) // ★
                                       .build();
        
        TypeSpec typeSpec = TypeSpec.classBuilder("Hoge")
                                    .addField(fieldSpec)
                                    .build();
        
        JavaFile javaFile = JavaFile.builder("sample.javapoet", typeSpec).build();
        
        javaFile.writeTo(System.out);
    }
}
```

```java:
package sample.javapoet;

import java.lang.String;
import java.util.List;

class Hoge {
  private List<String> list;
}
```

- `ParameterizedTypeName` を使って型 `TypeName` を宣言する。

##メソッドの追加
```java:
import java.io.IOException;

import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;

public class Main {
    public static void main(String... args) throws IOException {
        MethodSpec methodSpec = MethodSpec.methodBuilder("method") // ★
                                          .build();
        
        TypeSpec typeSpec = TypeSpec.classBuilder("Hoge")
                                    .addMethod(methodSpec) // ★
                                    .build();
        
        JavaFile javaFile = JavaFile.builder("sample.javapoet", typeSpec).build();
        
        javaFile.writeTo(System.out);
    }
}
```

```java:生成されたコード
package sample.javapoet;

class Hoge {
  void method() {
  }
}
```

###引数の宣言
```java:
import java.io.IOException;

import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.TypeSpec;

public class Main {
    public static void main(String... args) throws IOException {
        ParameterSpec parameterSpec = ParameterSpec.builder(String.class, "param") // ★
                                                   .build();
        
        MethodSpec methodSpec = MethodSpec.methodBuilder("method")
                                          .addParameter(parameterSpec) // ★
                                          .build();
        
        TypeSpec typeSpec = TypeSpec.classBuilder("Hoge")
                                    .addMethod(methodSpec)
                                    .build();
        
        JavaFile javaFile = JavaFile.builder("sample.javapoet", typeSpec).build();
        
        javaFile.writeTo(System.out);
    }
}
```

```java:
package sample.javapoet;

import java.lang.String;

class Hoge {
  void method(String param) {
  }
}
```

###可変長引数
```java:
import java.io.IOException;

import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.TypeSpec;

public class Main {
    public static void main(String... args) throws IOException {
        ParameterSpec parameterSpec = ParameterSpec.builder(String[].class, "params") // ★
                                                   .build();
        
        MethodSpec methodSpec = MethodSpec.methodBuilder("method")
                                          .addParameter(parameterSpec)
                                          .varargs(true) // ★
                                          .build();
        
        TypeSpec typeSpec = TypeSpec.classBuilder("Hoge")
                                    .addMethod(methodSpec)
                                    .build();
        
        JavaFile javaFile = JavaFile.builder("sample.javapoet", typeSpec).build();
        
        javaFile.writeTo(System.out);
    }
}
```

```java:生成されたコード
package sample.javapoet;

import java.lang.String;

class Hoge {
  void method(String... params) {
  }
}
```

- 最後に追加したパラメータが配列型になるようにして、 `varargs(true)` を指定する。

###戻り値の型を指定する
```java:
import java.io.IOException;

import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;

public class Main {
    public static void main(String... args) throws IOException {
        MethodSpec methodSpec = MethodSpec.methodBuilder("method")
                                          .returns(String.class) // ★
                                          .build();
        
        TypeSpec typeSpec = TypeSpec.classBuilder("Hoge")
                                    .addMethod(methodSpec)
                                    .build();
        
        JavaFile javaFile = JavaFile.builder("sample.javapoet", typeSpec).build();
        
        javaFile.writeTo(System.out);
    }
}
```

```java:生成されたコード
package sample.javapoet;

import java.lang.String;

class Hoge {
  String method() {
  }
}
```

###例外宣言
```java
import java.io.IOException;

import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;

public class Main {
    public static void main(String... args) throws IOException {
        MethodSpec methodSpec = MethodSpec.methodBuilder("method")
                                          .addException(Exception.class) // ★
                                          .build();
        
        TypeSpec typeSpec = TypeSpec.classBuilder("Hoge")
                                    .addMethod(methodSpec)
                                    .build();
        
        JavaFile javaFile = JavaFile.builder("sample.javapoet", typeSpec).build();
        
        javaFile.writeTo(System.out);
    }
}
```

```java:生成されたコード
package sample.javapoet;

import java.lang.Exception;

class Hoge {
  void method() throws Exception {
  }
}
```

###コードを記述する
```java:
import java.io.IOException;

import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;

public class Main {
    public static void main(String... args) throws IOException {
        MethodSpec methodSpec = MethodSpec.methodBuilder("method")
                                          .addCode("System.out.println(\"Hello JavaPoet!!\");\n") // ★
                                          .build();
        
        TypeSpec typeSpec = TypeSpec.classBuilder("Hoge")
                                    .addMethod(methodSpec)
                                    .build();
        
        JavaFile javaFile = JavaFile.builder("sample.javapoet", typeSpec).build();
        
        javaFile.writeTo(System.out);
    }
}
```

```java:生成されたコード
package sample.javapoet;

class Hoge {
  void method() {
    System.out.println("Hello JavaPoet!!");
  }
}
```

###書式指定
####`$L`：リテラル
```java:
import java.io.IOException;

import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;

public class Main {
    public static void main(String... args) throws IOException {
        MethodSpec methodSpec = MethodSpec.methodBuilder("method")
                                          .addCode("int i = $L;\n", 10) // ★
                                          .build();
        
        TypeSpec typeSpec = TypeSpec.classBuilder("Hoge")
                                    .addMethod(methodSpec)
                                    .build();
        
        JavaFile javaFile = JavaFile.builder("sample.javapoet", typeSpec).build();
        
        javaFile.writeTo(System.out);
    }
}
```

```java:生成されたコード
package sample.javapoet;

class Hoge {
  void method() {
    int i = 10;
  }
}
```

- `$L` は、リテラルとしてそのまま値を埋め込む。

####`$S`：String リテラル
```java:
import java.io.IOException;

import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;

public class Main {
    public static void main(String... args) throws IOException {
        MethodSpec methodSpec = MethodSpec.methodBuilder("method")
                                          .addCode("String s = $S\n", "string!") // ★
                                          .build();
        
        TypeSpec typeSpec = TypeSpec.classBuilder("Hoge")
                                    .addMethod(methodSpec)
                                    .build();
        
        JavaFile javaFile = JavaFile.builder("sample.javapoet", typeSpec).build();
        
        javaFile.writeTo(System.out);
    }
}
```

```java:生成されたコード
package sample.javapoet;

class Hoge {
  void method() {
    String s = "string!"
  }
}
```

- `$S` は、文字列リテラルとして埋め込まれる。

####`$T`：型を埋め込む
```java:
import java.io.IOException;
import java.util.Date;

import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;

public class Main {
    public static void main(String... args) throws IOException {
        MethodSpec methodSpec = MethodSpec.methodBuilder("method")
                                          .addCode("$T date = new $T();\n", Date.class, Date.class) // ★
                                          .build();
        
        TypeSpec typeSpec = TypeSpec.classBuilder("Hoge")
                                    .addMethod(methodSpec)
                                    .build();
        
        JavaFile javaFile = JavaFile.builder("sample.javapoet", typeSpec).build();
        
        javaFile.writeTo(System.out);
    }
}
```

```java:生成されたコード
package sample.javapoet;

import java.util.Date;

class Hoge {
  void method() {
    Date date = new Date();
  }
}
```

- `$T` は、 `Class` オブジェクトを指定することで型の宣言などを埋め込むことができる。

####`$N`：変数やメソッドを参照する
```java:
import java.io.IOException;

import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.TypeSpec;

public class Main {
    public static void main(String... args) throws IOException {
        MethodSpec methodSpec1 = MethodSpec.methodBuilder("method1")
                                           .returns(String.class)
                                           .addCode("return $S;\n", "hoehoge")
                                           .build();
        
        ParameterSpec parameterSpec = ParameterSpec.builder(String.class, "param").build();
        
        MethodSpec methodSpec2 = MethodSpec.methodBuilder("method2")
                                          .addParameter(parameterSpec)
                                          .addCode("System.out.println(this.$N() + $N);\n", methodSpec1, parameterSpec) // ★
                                          .build();
        
        TypeSpec typeSpec = TypeSpec.classBuilder("Hoge")
                                    .addMethod(methodSpec1)
                                    .addMethod(methodSpec2)
                                    .build();
        
        JavaFile javaFile = JavaFile.builder("sample.javapoet", typeSpec).build();
        
        javaFile.writeTo(System.out);
    }
}
```

```java:生成されたコード
package sample.javapoet;

import java.lang.String;

class Hoge {
  String method1() {
    return "hoehoge";
  }

  void method2(String param) {
    System.out.println(this.method1() + param);
  }
}
```

- `$N` で、 `ParameterSpec` や `MethodSpec` を埋め込める。

###ステートメントの追加
```java:
import java.io.IOException;

import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;

public class Main {
    public static void main(String... args) throws IOException {
        MethodSpec methodSpec = MethodSpec.methodBuilder("method")
                                          .addStatement("System.out.println($S)", "hogehoge") // ★
                                          .build();
        
        TypeSpec typeSpec = TypeSpec.classBuilder("Hoge")
                                    .addMethod(methodSpec)
                                    .build();
        
        JavaFile javaFile = JavaFile.builder("sample.javapoet", typeSpec).build();
        
        javaFile.writeTo(System.out);
    }
}
```

```java:生成されたコード
package sample.javapoet;

class Hoge {
  void method() {
    System.out.println("hogehoge");
  }
}
```

- `addCode()` と比べると、改行と行末のセミコロンが不要になる。

###制御フローの開始と終了
```java:
import java.io.IOException;

import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;

public class Main {
    public static void main(String... args) throws IOException {
        MethodSpec methodSpec = MethodSpec.methodBuilder("method")
                                          .beginControlFlow("try") // ★
                                          .addStatement("System.out.println($S)", "Hello World!!") // ★
                                          .nextControlFlow("catch($T e)", Exception.class) // ★
                                          .addStatement("e.printStackTrace()") // ★
                                          .nextControlFlow("finally") // ★
                                          .addStatement("// nothing") // ★
                                          .endControlFlow() // ★
                                          .build();
        
        TypeSpec typeSpec = TypeSpec.classBuilder("Hoge")
                                    .addMethod(methodSpec)
                                    .build();
        
        JavaFile javaFile = JavaFile.builder("sample.javapoet", typeSpec).build();
        
        javaFile.writeTo(System.out);
    }
}
```

```java:生成されたコード
package sample.javapoet;

import java.lang.Exception;

class Hoge {
  void method() {
    try {
      System.out.println("Hello World!!");
    } catch(Exception e) {
      e.printStackTrace();
    } finally {
      // nothing;
    }
  }
}
```

- `beginControlFlow()` で制御フローを開始し、  
`nextControlFlow()` で制御フローを区切り、  
`endControlFlow()` で制御フローを終了させる（省略可）
- `if` 文とか、 `while` 文とか、 `switch` 文とかはこれで書ける。

##コンストラクタ
```java:
import java.io.IOException;

import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;

public class Main {
    public static void main(String... args) throws IOException {
        MethodSpec constructor = MethodSpec.constructorBuilder().build(); // ★
        
        TypeSpec typeSpec = TypeSpec.classBuilder("Hoge")
                                    .addMethod(constructor) // ★
                                    .build();
        
        JavaFile javaFile = JavaFile.builder("sample.javapoet", typeSpec).build();
        
        javaFile.writeTo(System.out);
    }
}
```

```java:
package sample.javapoet;

class Hoge {
  Hoge() {
  }
}
```

- `MethodSpec#constructorBuilder()` で作る。
- あとはメソッドの場合と同じ。

#インターフェースの定義
```java:
import java.io.IOException;

import javax.lang.model.element.Modifier;

import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;

public class Main {
    public static void main(String... args) throws IOException {
        MethodSpec methodSpec = MethodSpec.methodBuilder("method")
                                          .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
                                          .build();
        
        TypeSpec typeSpec = TypeSpec.interfaceBuilder("MyInterface") // ★
                                    .addMethod(methodSpec)
                                    .build();
        
        JavaFile javaFile = JavaFile.builder("sample.javapoet", typeSpec).build();
        
        javaFile.writeTo(System.out);
    }
}
```

```java:生成されたコード
package sample.javapoet;

interface MyInterface {
  void method();
}
```

- `TypeSpec#interfaceBuilder()` で作成する。
- メソッドは、 `Modifier` として `PUBLIC` と `ABSTRACT` が設定されていなければならない。

#enum を定義する
```java:
import java.io.IOException;

import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.TypeSpec;

public class Main {
    public static void main(String... args) throws IOException {
        TypeSpec typeSpec = TypeSpec.enumBuilder("MyEnum") // ★
                                    .addEnumConstant("HOGE")
                                    .addEnumConstant("FUGA")
                                    .addEnumConstant("PIYO")
                                    .build();
        
        JavaFile javaFile = JavaFile.builder("sample.javapoet", typeSpec).build();
        
        javaFile.writeTo(System.out);
    }
}
```

```java:生成されたコード
package sample.javapoet;

enum MyEnum {
  HOGE,

  FUGA,

  PIYO
}
```

##コンストラクタを定義する
```java:
import java.io.IOException;

import javax.lang.model.element.Modifier;

import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;

public class Main {
    public static void main(String... args) throws IOException {
        FieldSpec fieldSpec = FieldSpec.builder(String.class, "value", Modifier.PRIVATE, Modifier.FINAL)
                                       .build();
        
        MethodSpec constructorSpec = MethodSpec.constructorBuilder()
                                               .addModifiers(Modifier.PRIVATE)
                                               .addParameter(String.class, "value")
                                               .addStatement("this.$N = value", fieldSpec)
                                               .build();
        
        TypeSpec typeSpec = TypeSpec.enumBuilder("MyEnum")
                                    .addEnumConstant("HOGE", TypeSpec.anonymousClassBuilder("$S", "hoge").build()) // ★
                                    .addMethod(constructorSpec)
                                    .addField(fieldSpec)
                                    .build();
        
        JavaFile javaFile = JavaFile.builder("sample.javapoet", typeSpec).build();
        
        javaFile.writeTo(System.out);
    }
}
```

```java:生成されたコード
package sample.javapoet;

import java.lang.String;

enum MyEnum {
  HOGE("hoge");

  private final String value;

  private MyEnum(String value) {
    this.value = value;
  }
}
```

##抽象メソッドをオーバーライドする
```java:
import java.io.IOException;

import javax.lang.model.element.Modifier;

import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;

public class Main {
    public static void main(String... args) throws IOException {
        MethodSpec methodSpec = MethodSpec.methodBuilder("method")
                                          .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
                                          .build();
        
        TypeSpec anonymous = TypeSpec.anonymousClassBuilder("")
                                     .addMethod(MethodSpec.methodBuilder(methodSpec.name) // ★
                                                 .addModifiers(Modifier.PUBLIC)
                                                 .addAnnotation(Override.class)
                                                 .build())
                                     .build();
        
        TypeSpec typeSpec = TypeSpec.enumBuilder("MyEnum")
                                    .addEnumConstant("HOGE", anonymous)
                                    .addMethod(methodSpec)
                                    .build();
        
        JavaFile javaFile = JavaFile.builder("sample.javapoet", typeSpec).build();
        
        javaFile.writeTo(System.out);
    }
}
```

```java:生成されたコード
package sample.javapoet;

import java.lang.Override;

enum MyEnum {
  HOGE {
    @Override
    public void method() {
    }
  };

  public abstract void method();
}
```

#アノテーションを定義する
```java:
import java.io.IOException;

import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.TypeSpec;

public class Main {
    public static void main(String... args) throws IOException {
        TypeSpec typeSpec = TypeSpec.annotationBuilder("MyAnnotation") // ★
                                    .build();
        
        JavaFile javaFile = JavaFile.builder("sample.javapoet", typeSpec).build();
        
        javaFile.writeTo(System.out);
    }
}
```

```java:生成されたコード
package sample.javapoet;

@interface MyAnnotation {
}
```

##属性（メソッド）の定義
```java:
import java.io.IOException;

import javax.lang.model.element.Modifier;

import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;

public class Main {
    public static void main(String... args) throws IOException {
        MethodSpec methodSpec = MethodSpec.methodBuilder("value")
                                          .returns(String.class)
                                          .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) // ★
                                          .defaultValue("$S", "hoge")
                                          .build();
        
        TypeSpec typeSpec = TypeSpec.annotationBuilder("MyAnnotation")
                                    .addMethod(methodSpec) // ★
                                    .build();
        
        JavaFile javaFile = JavaFile.builder("sample.javapoet", typeSpec).build();
        
        javaFile.writeTo(System.out);
    }
}
```

```java:生成されたコード
package sample.javapoet;

import java.lang.String;

@interface MyAnnotation {
  String value() default "hoge";
}
```

- メソッドの `Modifier` には、 `PUBLIC` と `ABSTRACT` を設定する。

#匿名クラス
```java:
import java.io.IOException;

import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.TypeSpec;

public class Main {
    public static void main(String... args) throws IOException {
        TypeSpec anonymous = TypeSpec.anonymousClassBuilder("").build(); // ★
        
        FieldSpec fieldSpec = FieldSpec.builder(Object.class, "obj")
                                       .initializer("$L", anonymous) // ★
                                       .build();
        
        TypeSpec typeSpec = TypeSpec.classBuilder("MyAnnotation")
                                    .addField(fieldSpec)
                                    .build();
        
        JavaFile javaFile = JavaFile.builder("sample.javapoet", typeSpec).build();
        
        javaFile.writeTo(System.out);
    }
}
```

```java:生成されたコード
package sample.javapoet;

import java.lang.Object;

class Hoge {
  Object obj = new Object() {
  };
}
```

- `TypeSpec.anonymousClassBuilder()` で作成して、 `$L` で埋め込む。

#ファイル出力
```java:
import java.io.File;
import java.io.IOException;

import javax.lang.model.element.Modifier;

import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.TypeSpec;

public class Main {
    public static void main(String... args) throws IOException {
        TypeSpec typeSpec = TypeSpec.classBuilder("Hoge")
                                    .addModifiers(Modifier.PUBLIC)
                                    .build();
        
        JavaFile javaFile = JavaFile.builder("sample.javapoet", typeSpec).build();
        
        javaFile.writeTo(new File(".")); // ★
    }
}
```

```text:ファイル出力結果
`-sample/javapoet/
   `-Hoge.java
```

- `JavaFile#writeTo(File)` で、引数にディレクトリを指す `File` オブジェクトを渡せば、その下にパッケージ階層を作った上でソースコードを出力してくれる。

#Class オブジェクトを取得できない型を使用する
```java:
import java.io.IOException;

import javax.lang.model.element.Modifier;

import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.TypeSpec;

public class Main {
    public static void main(String... args) throws IOException {
        ClassName className = ClassName.get("sample.javapoet.other", "Fuga"); // ★
        
        FieldSpec fieldSpec = FieldSpec.builder(className, "fuga", Modifier.PRIVATE) // ★
                                       .build();
        
        TypeSpec typeSpec = TypeSpec.classBuilder("Hoge")
                                    .addField(fieldSpec)
                                    .build();
        
        JavaFile javaFile = JavaFile.builder("sample.javapoet", typeSpec).build();
        
        javaFile.writeTo(System.out);
    }
}
```

```java:生成されたコード
package sample.javapoet;

import sample.javapoet.other.Fuga;

class Hoge {
  private Fuga fuga;
}
```



#参考
- [square/javapoet | GitHub](https://github.com/square/javapoet)