JSONデータ/JSON SchemaからJavaマッパークラスを生成する方法および、オプションについて

# 目的
XMLよりJSONのほうがデータ量が少なくなるため、JSONデータからJavaマッパークラスを生成する方法について調べてみた。

# 結果
「jsonschema2pojo-core」ライブラリを使って「Jackson」形式のJavaマッパークラスを自動生成出来た。
Javaマッパークラスのアノテーション形式については「Jackson 2.x、Jackson 1.x、Gson、None」から選べる。
[Web](http://www.jsonschema2pojo.org/)/maven/gradle/cliからも利用できる。

# 自動生成結果での注意事項
クラス名がかぶると「name_.java」のように別名でクラスが生成されます。
JSONデータから生成する際、array要素が0または、1つの場合に期待した出力と食い違う場合があります。

# 補足
そもそもなんで、クラスなんて作るのってところはeclipseで補完機能使いたかったから。
ちょこっと扱いたいなら、以下のように書けばオブジェクトを取得できる。
「org.json:json:20080701.jar」使用。

```java
org.json.JSONObject jsonObject = new org.json.JSONObject(jsonString);
```

# 環境
* Windows 10 Pro 1511 (x64)
* JDK8 u73
* Eclipse IDE for Java Developers Mars 2
* jsonschema2pojo-core
 * 0.4.21

# ビルド設定
build.gradle

```gradle
apply plugin: 'java'

repositories { mavenCentral() }


// set encoding
def defaultEncoding = 'UTF-8'
tasks.withType(AbstractCompile).each { it.options.encoding = defaultEncoding }
tasks.withType(GroovyCompile).each { it.groovyOptions.encoding = defaultEncoding }

dependencies {

  // JOSN -> Java用
  compile 'org.jsonschema2pojo:jsonschema2pojo-core:0.4.21';
  testCompile 'junit:junit:4.12'

}
```

# サンプルソース
設定については「DefaultGenerationConfig」を継承してメソッドをオーバーライドする形となる。
JSONToJava.java

```java
package sample.rest.json.client.generator;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.logging.Logger;

import org.jsonschema2pojo.DefaultGenerationConfig;
import org.jsonschema2pojo.GenerationConfig;
import org.jsonschema2pojo.Jackson2Annotator;
import org.jsonschema2pojo.SchemaGenerator;
import org.jsonschema2pojo.SchemaMapper;
import org.jsonschema2pojo.SchemaStore;
import org.jsonschema2pojo.SourceType;
import org.jsonschema2pojo.rules.RuleFactory;

import com.sun.codemodel.JCodeModel;

public class JSONToJava {

  private static final Logger log = Logger.getLogger(JSONToJava.class.getName());

  public static void main(String[] args) {

    Path outputPath = null;
    try {
      StringBuilder jsonStringBuilder = new StringBuilder();
      jsonStringBuilder.append("{");
      jsonStringBuilder.append(" \"name\": \"foor\",");
      jsonStringBuilder.append(" \"age\": 18");
      jsonStringBuilder.append("}");
      outputPath = Files.createTempDirectory(null);
      String packageName = "sandbox.foo";
      String rootClassName = "Root";
      JSONToJava jsonToJava =
          new JSONToJava(jsonStringBuilder.toString(), outputPath, packageName, rootClassName);
      jsonToJava.execute();
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      log.info("「" + outputPath + "」に出力しました。");
    }
  }


  private String jsonString;
  private Path outputPath;
  private String packageName;
  private String rootClassName;

  public JSONToJava(String jsonString, Path outputPath, String packageName, String rootClassName) {
    this.jsonString = jsonString;
    this.outputPath = outputPath;
    this.packageName = packageName;
    this.rootClassName = rootClassName;
  }

  public void execute() throws IOException {

    JCodeModel codeModel = new JCodeModel();
    GenerationConfig generationConfig = new DefaultGenerationConfig() {
      @Override
      public SourceType getSourceType() {
        return SourceType.JSON;
      }

      @Override
      public boolean isIncludeHashcodeAndEquals() {
        return false;
      }

      @Override
      public boolean isIncludeToString() {
        return false;
      }

      @Override
      public boolean isIncludeAdditionalProperties() {
        return false;
      }

      @Override
      public boolean isIncludeDynamicAccessors() {
        return false;
      }
    };

    SchemaMapper mapper = new SchemaMapper(
        new RuleFactory(generationConfig, new Jackson2Annotator(), new SchemaStore()),
        new SchemaGenerator());
    mapper.generate(codeModel, rootClassName, packageName, jsonString);

    codeModel.build(outputPath.toFile());
  }

}
```

# 入力データ（JSONデータ）

```json
{
 "name": "foor",
 "age": 18
}
```

# 出力結果（Javaマッパークラス）
Root.java

```java

package sandbox.foo;

import javax.annotation.Generated;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

@JsonInclude(JsonInclude.Include.NON_NULL)
@Generated("org.jsonschema2pojo")
@JsonPropertyOrder({
    "name",
    "age"
})
public class Root {

    @JsonProperty("name")
    private String name;
    @JsonProperty("age")
    private Integer age;

    /**
     * 
     * @return
     *     The name
     */
    @JsonProperty("name")
    public String getName() {
        return name;
    }

    /**
     * 
     * @param name
     *     The name
     */
    @JsonProperty("name")
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 
     * @return
     *     The age
     */
    @JsonProperty("age")
    public Integer getAge() {
        return age;
    }

    /**
     * 
     * @param age
     *     The age
     */
    @JsonProperty("age")
    public void setAge(Integer age) {
        this.age = age;
    }

}
```

# 生成オプション
org.jsonschema2pojo.DefaultGenerationConfig

|メソッド名|戻り値（型）|デフォルト値||
|---|---|---|---|
|getSource()|Iterator<URL>|Exception|入力ファイル/ディレクトリ指定|
|getSourceType()|SourceType|SourceType.JSONSCHEMA|入力種別指定（jsonschema、json）|
|getTargetDirectory()|File|new File(".")|出力先ディレクトリ指定|
|isRemoveOldOutput()|boolean|false|出力ディレクトリ削除|
|getTargetPackage()|String|""|出力パッケージ名の指定|
|getOutputEncoding()|String|UTF-8|出力文字コード|
|getTargetVersion()|String|1.6|対象バージョン指定|
|isGenerateBuilders()|boolean|false|builder作成|
|isUsePrimitives()|boolean|false|プリミティブ変数の使用|
|getPropertyWordDelimiters()|char[]|new char[] { '-', ' ', '_' }|フィールド名生成時に除去される文字列|
|isUseLongIntegers()|boolean|false|json(integer)の場合longの使用|
|isUseDoubleNumbers()|boolean|true|json(number)の場合doubleの使用|
|isIncludeHashcodeAndEquals()|boolean|true|toHash()、toEquals()の生成（commons.lang)|
|isIncludeToString()|boolean|true|toString()の生成（commons.lang)|
|getAnnotationStyle()|AnnotationStyle|AnnotationStyle.JACKSON|アノテーションスタイル（Jackson 2.x、Jackson 1.x、Gson、None）|
|getCustomAnnotator()|Class<? extends Annotator>|NoopAnnotator.class|カスタムアノテーション|
|getCustomRuleFactory()|Class<? extends RuleFactory>|RuleFactory.class|カスタムルールファクトリー|
|isIncludeJsr303Annotations()|boolean|false|JSR303アノテーション（Bean Validation）出力|
|isUseJodaDates()|boolean|false|org.joda.time.DateTime使用|
|isUseJodaLocalDates()|boolean|false|org.joda.time.LocalDate使用|
|isUseJodaLocalTimes()|boolean|false|org.joda.time.LocalTime使用|
|isUseCommonsLang3()|boolean|false|commons-langをcommons-lang3に置き換え|
|isParcelable()|boolean|false|Parcelable実装（Android）|
|getFileFilter()|FileFilter|new AllFileFilter()|入力ディレクトリ指定の場合使用可能|
|isInitializeCollections()|boolean|true|コレクションの初期化|
|getClassNamePrefix()|String|""|接頭語|
|getClassNameSuffix()|String|""|接尾語|
|isIncludeConstructors()|boolean|false|コンストラクタ生成|
|isConstructorsRequiredPropertiesOnly()|boolean|false|コンストラクタ生成時必須項目のみ|
|isIncludeAdditionalProperties()|boolean|true|追加プロパティの許可|
|isIncludeAccessors()|boolean|true|get/set生成|
|isIncludeDynamicAccessors()|boolean|true|declaredPropertyが生成される|
|getDateTimeType()|String|null|日付型指定（例：java.time.LocalDateTime）（優先）|
|getDateType()|String|null|日付型指定（例：java.time.LocalDate）（優先）|
|getTimeType()|String|null|日付型指定（例：java.time.LocalTime）（優先）|

# 参考資料
[jsonschema2pojo](https://github.com/joelittlejohn/jsonschema2pojo)
[jsonschema2pojo Web版](http://www.jsonschema2pojo.org/)