目的
XMLよりJSONのほうがデータ量が少なくなるため、JSONデータからJavaマッパークラスを生成する方法について調べてみた。
結果
「jsonschema2pojo-core」ライブラリを使って「Jackson」形式のJavaマッパークラスを自動生成出来た。
Javaマッパークラスのアノテーション形式については「Jackson 2.x、Jackson 1.x、Gson、None」から選べる。
Web/maven/gradle/cliからも利用できる。
自動生成結果での注意事項
クラス名がかぶると「name_.java」のように別名でクラスが生成されます。
JSONデータから生成する際、array要素が0または、1つの場合に期待した出力と食い違う場合があります。
補足
そもそもなんで、クラスなんて作るのってところはeclipseで補完機能使いたかったから。
ちょこっと扱いたいなら、以下のように書けばオブジェクトを取得できる。
「org.json:json:20080701.jar」使用。
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
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
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データ)
{
"name": "foor",
"age": 18
}
出力結果(Javaマッパークラス)
Root.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 | 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)(優先) |