1前書き

この記事では、JSONデータをシリアライズおよびデシリアライズするためのhttp://code.google.com/p/google-gson[Gson]およびhttps://github.com/FasterXML/jackson[Jackson]APIを比較しますJavaオブジェクトとその逆。

GsonとJacksonは、Java用のJSONデータバインディングサポートを提供する完全なライブラリです。それぞれが積極的に開発されたオープンソースプロジェクトで、複雑なデータ型の処理とJava Genericsのサポートを提供します。

ほとんどの場合、両方のライブラリはエンティティクラスを変更せずにエンティティへのシリアル化を解除できます。これは開発者がエンティティのソースコードにアクセスできない場合に重要です。


2 Gson Mavenの依存関係

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>${gson.version}</version>
</dependency>

Gsonの最新版を入手することができます。[ここに]。


3 Gsonシリアライゼーション

直列化は、JavaオブジェクトをJSON出力に変換します。次のエンティティを検討してください。

public class ActorGson {
    private String imdbId;
    private Date dateOfBirth;
    private List<String> filmography;

   //getters and setters, default constructor and field constructor omitted
}

public class Movie {
    private String imdbId;
    private String director;
    private List<ActorGson> actors;

   //getters and setters, default constructor and field constructor omitted
}


3.1. 単純シリアライゼーション

JavaからJSONへのシリアル化の例から始めましょう。

SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");

ActorGson rudyYoungblood = new ActorGson(
  "nm2199632",
  sdf.parse("21-09-1982"),
  Arrays.asList("Apocalypto",
  "Beatdown", "Wind Walkers")
);
Movie movie = new Movie(
  "tt0472043",
  "Mel Gibson",
  Arrays.asList(rudyYoungblood));

String serializedMovie = new Gson().toJson(movie);

これは次のようになります。

{
    "imdbId": "tt0472043",
    "director": "Mel Gibson",
    "actors":[{
        "imdbId": "nm2199632",
        "dateOfBirth": "Sep 21, 1982 12:00:00 AM",
        "filmography":["Apocalypto", "Beatdown", "Wind Walkers"]    }]}

デフォルトでは:


  • null

    値がないため、すべてのプロパティはシリアル化されています


  • dateOfBirth

    フィールドはデフォルトのGson日付パターンで変換されました

  • 出力はフォーマットされておらず、JSONプロパティ名はJavaに対応しています

実体


3.2. カスタムシリアル化

カスタムシリアライザを使用すると、標準の動作を変更できます。 HTMLで出力フォーマッタを導入する、

null

値を処理する、出力からプロパティを除外する、または新しい出力を追加することができます。


ActorGsonSerializer

は、

ActorGson

要素のJSONコードの生成を変更します。

public class ActorGsonSerializer implements JsonSerializer<ActorGson> {
    private SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");

    @Override
    public JsonElement serialize(ActorGson actor, Type type,
        JsonSerializationContext jsonSerializationContext) {

        JsonObject actorJsonObj = new JsonObject();

        actorJsonObj.addProperty("<strong>IMDB Code</strong>", actor.getImdbId());

        actorJsonObj.addProperty("<strong>Date Of Birth</strong>",
          actor.getDateOfBirth() != null ?
          sdf.format(actor.getDateOfBirth()) : null);

        actorJsonObj.addProperty("<strong>N° Film:</strong> ",
          actor.getFilmography()  != null ?
          actor.getFilmography().size() : null);

        actorJsonObj.addProperty("filmography", actor.getFilmography() != null ?
          convertFilmography(actor.getFilmography()) : null);

        return actorJsonObj;
    }

    private String convertFilmography(List<String> filmography) {
        return filmography.stream()
          .collect(Collectors.joining("-"));
    }
}


director

プロパティを除外するために、考慮したいプロパティに

@ Expose

アノテーションを使用します。

public class MovieWithNullValue {

    @Expose
    private String imdbId;
    private String director;

    @Expose
    private List<ActorGson> actors;
}

これで

GsonBuilder

クラスを使用してGsonオブジェクトの作成を進めることができます。

Gson gson = new GsonBuilder()
  .setPrettyPrinting()
  .excludeFieldsWithoutExposeAnnotation()
  .serializeNulls()
  .disableHtmlEscaping()
  .registerTypeAdapter(ActorGson.class, new ActorGsonSerializer())
  .create();

SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");

ActorGson rudyYoungblood = new ActorGson("nm2199632",
  sdf.parse("21-09-1982"), Arrays.asList("Apocalypto","Beatdown", "Wind Walkers"));

MovieWithNullValue movieWithNullValue = new MovieWithNullValue(null,
  "Mel Gibson", Arrays.asList(rudyYoungblood));

String serializedMovie = gson.toJson(movieWithNullValue);

結果は次のとおりです。

{
  "imdbId": null,
  "actors":[    {
      "<strong>IMDB Code</strong>": "nm2199632",
      "<strong>Date Of Birth</strong>": "21-09-1982",
      "<strong>N° Film:</strong> ": 3,
      "filmography": "Apocalypto-Beatdown-Wind Walkers"
    }
 ]}

次のことに注意してください。

  • 出力はフォーマットされています

  • いくつかのプロパティ名は変更されていてHTMLを含んでいます


  • null

    値が含まれ、

    director

    フィールドが省略されている


  • Date

    は現在

    dd-MM-yyyy

    形式になっています

  • 新しい性質が存在します –

    N°Film

  • filmographyはフォーマットされたプロパティであり、デフォルトのJSONリストではありません


4 Gsonデシリアライゼーション


4.1. 単純なシリアル化解除

逆シリアル化はJSON入力をJavaオブジェクトに変換します。出力を説明するために、両方のエンティティクラスに

toString()

メソッドを実装します。

public class Movie {
    @Override
    public String toString() {
      return "Movie[imdbId=" + imdbId + ", director=" + director + ",actors=" + actors + "]";
    }
    ...
}

public class ActorGson {
    @Override
    public String toString() {
        return "ActorGson[imdbId=" + imdbId + ", dateOfBirth=" + dateOfBirth +
          ",filmography=" + filmography + "]";
    }
    ...
}

それから、シリアライズされたJSONを利用し、それを標準のGsonデシリアライゼーションを通して実行します。

String jsonInput = "{\"imdbId\":\"tt0472043\",\"actors\":" +
  "[{\"imdbId\":\"nm2199632\",\"dateOfBirth\":\"1982-09-21T12:00:00+01:00\"," +
  "\"filmography\":[\"Apocalypto\",\"Beatdown\",\"Wind Walkers\"]}]}";

Movie outputMovie = new Gson().fromJson(jsonInput, Movie.class);
outputMovie.toString();

出力は私たちのエンティティであり、JSON入力からのデータが入力されています。

Movie[imdbId=tt0472043, director=null, actors=[ActorGson
 [imdbId=nm2199632, dateOfBirth=Tue Sep 21 04:00:00 PDT 1982,
  filmography=[Apocalypto, Beatdown, Wind Walkers]]]]----

単純なシリアライザの場合と同様に、

**  JSON入力名はJavaエンティティ名と一致している必要があります。

それらはnullに設定されます。

**  __dateOfBirth__フィールドは、デフォルトのGsonの日付パターンで変換されました。

タイムゾーンを無視します。

====  **  4.2. カスタム逆シリアル化**

カスタムのデシリアライザを使用すると、標準のデシリアライザの動作を変更できます。この場合、__dateOfBirth__の正しいタイムゾーンを日付に反映させる必要があります。これを実現するには、__ActorGson__エンティティにカスタム__ActorGsonDeserializer__を使用します。

[source,java,gutter:,true]

public class ActorGsonDeserializer implements JsonDeserializer<ActorGson> {

private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");

@Override
public ActorGson deserialize(JsonElement json, Type type,
  JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {

JsonObject jsonObject = json.getAsJsonObject();

JsonElement jsonImdbId = jsonObject.get("imdbId");
JsonElement jsonDateOfBirth = jsonObject.get("dateOfBirth");
JsonArray jsonFilmography = jsonObject.getAsJsonArray("filmography");

ArrayList<String> filmList = new ArrayList<String>();
if (jsonFilmography != null) {
    for (int i = 0; i < jsonFilmography.size(); i++) {
        filmList.add(jsonFilmography.get(i).getAsString());
    }
}

    ActorGson actorGson = new ActorGson(jsonImdbId.getAsString(),
      sdf.parse(jsonDateOfBirth.getAsString()), filmList);
        return actorGson;
    }
}

タイムゾーンを考慮して、入力日付を解析するために__SimpleDateFormat__パーサーを使用しました。

Dateに対してのみカスタムのデシリアライザを作成することにしたかもしれませんが、__ActorGsonDeserializer__はデシリアライゼーションプロセスのより詳細なビューを提供します。

また、Gsonのアプローチでは__ActorGson__エンティティを変更する必要がないことに注意してください。これは、入力エンティティに常にアクセスできるとは限らないため理想的です。ここではカスタムのデシリアライザを使用します。

[source,java,gutter:,true]

String jsonInput = “{\”imdbId\”:\”tt0472043\”,\”actors\”:”
+ “[{\”imdbId\”:\”nm2199632\”,\”dateOfBirth\”:\”1982-09-21T12:00:00+01:00\”,
+ \”filmography\”:[\”Apocalypto\”,\”Beatdown\”,\”Wind Walkers\”]}]}”;

Gson gson = new GsonBuilder()
.registerTypeAdapter(ActorGson.class,new ActorGsonDeserializer())
.create();

Movie outputMovie = gson.fromJson(jsonInput, Movie.class);
outputMovie.toString();

日付が正しいタイムゾーンを使用することを除いて、出力は単純なデシリアライザの結果に似ています。

[source,java,gutter:,true]

Movie[imdbId=tt0472043, director=null, actors=[ActorGson
[imdbId=nm2199632, dateOfBirth=Tue Sep 21 12:00:00 PDT 1982,
filmography=[Apocalypto, Beatdown, Wind Walkers]]]]—-


5ジャクソンメイブン依存

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>${jackson.version}</version>
</dependency>

あなたはジャクソンの最新版を入手することができます%22[ここ]


6. ジャクソンシリアライゼーション


6.1. 単純シリアライゼーション

ここでは、Jacksonを使用して、次のエンティティを使用してGsonと同じシリアル化されたコンテンツを取得します。エンティティのゲッター/セッターは公開されている必要があります。

public class ActorJackson {
    private String imdbId;
    private Date dateOfBirth;
    private List<String> filmography;

   //required getters and setters, default constructor
   //and field constructor details omitted
}

public class Movie {
    private String imdbId;
    private String director;
    private List<ActorJackson> actors;

   //required getters and setters, default constructor
   //and field constructor details omitted
}
SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");
ActorJackson rudyYoungblood = new ActorJackson("nm2199632",sdf.parse("21-09-1982"),
  Arrays.asList("Apocalypto","Beatdown","Wind Walkers") );
Movie movie = new Movie("tt0472043","Mel Gibson", Arrays.asList(rudyYoungblood));
ObjectMapper mapper = new ObjectMapper();
String jsonResult = mapper.writeValueAsString(movie);

出力は次のとおりです。

{"imdbId":"tt0472043","director":"Mel Gibson","actors":[{"imdbId":"nm2199632","dateOfBirth":401439600000,
"filmography":["Apocalypto","Beatdown","Wind Walkers"]}]}

いくつかの興味深いメモ:

  • ObjectObject Mapは、Jacksonのシリアライザ/デシリアライザです。

  • 出力JSONはフォーマットされていません

  • デフォルトでは、Java Dateは

    long

    値に変換されます


6.2. カスタムシリアル化

エンティティのStdSerializerを拡張することで、

ActorJackson

要素生成用のJacksonシリアライザを作成できます。エンティティゲッター/セッターは公開されている必要があります。

public class ActorJacksonSerializer extends StdSerializer<ActorJackson> {

    private SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");

    public ActorJacksonSerializer(Class t) {
        super(t);
    }

    @Override
    public void serialize(ActorJackson actor, JsonGenerator jsonGenerator,
      SerializerProvider serializerProvider) throws IOException {

        jsonGenerator.writeStartObject();
        jsonGenerator.writeStringField("imdbId", actor.getImdbId());
        jsonGenerator.writeObjectField("dateOfBirth",
          actor.getDateOfBirth() != null ?
          sdf.format(actor.getDateOfBirth()) : null);

        jsonGenerator.writeNumberField("N° Film: ",
          actor.getFilmography() != null ? actor.getFilmography().size() : null);
    jsonGenerator.writeStringField("filmography", actor.getFilmography()
          .stream().collect(Collectors.joining("-")));

        jsonGenerator.writeEndObject();
    }
}


director

フィールドを無視できるようにMovieエンティティを作成します。

public class MovieWithNullValue {

    private String imdbId;

    @JsonIgnore
    private String director;

    private List<ActorJackson> actors;

   //required getters and setters, default constructor
   //and field constructor details omitted
}

これで、カスタムのObjectMapperの作成と設定に進むことができます。

SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");

ActorJackson rudyYoungblood = new ActorJackson(
  "nm2199632",
  sdf.parse("21-09-1982"),
  Arrays.asList("Apocalypto", "Beatdown","Wind Walkers"));
MovieWithNullValue movieWithNullValue =
  new MovieWithNullValue(null,"Mel Gibson", Arrays.asList(rudyYoungblood));

SimpleModule module = new SimpleModule();
module.addSerializer(new ActorJacksonSerializer(ActorJackson.class));
ObjectMapper mapper = new ObjectMapper();
String jsonResult = mapper.registerModule(module)
  .writer(new DefaultPrettyPrinter())
  .writeValueAsString(movieWithNullValue);

出力は、

null

値を処理し、日付をフォーマットし、

director

フィールドを除外し、



の新しい出力を表示するフォーマット済みJSONです。

{
  "actors" :[{
    "imdbId" : "nm2199632",
    "dateOfBirth" : "21-09-1982",
    "N° Film: " : 3,
    "filmography" : "Apocalypto-Beatdown-Wind Walkers"
  }],
  "imdbID" : null
}


7. ジャクソンの逆シリアル化


7.1. 単純なシリアル化解除

出力を説明するために、両方のJacksonエンティティークラスに

toString()

メソッドを実装します。

public class Movie {
    @Override
    public String toString() {
        return "Movie[imdbId=" + imdbId + ", director=" + director
          + ", actors=" + actors + "]";
    }
    ...
}

public class ActorJackson {
    @Override
    public String toString() {
        return "ActorJackson[imdbId=" + imdbId + ", dateOfBirth=" + dateOfBirth
          + ", filmography=" + filmography + "]";
    }
    ...
}

それから、シリアライズされたJSONを利用して、Jacksonのデシリアライゼーションを介して実行します。

String jsonInput = "{\"imdbId\":\"tt0472043\",\"actors\":
 [{\"imdbId\":\"nm2199632\",\"dateOfBirth\":\"1982-09-21T12:00:00+01:00\",
  \"filmography\":[\"Apocalypto\",\"Beatdown\",\"Wind Walkers\"]}]}";
ObjectMapper mapper = new ObjectMapper();
Movie movie = mapper.readValue(jsonInput, Movie.class);

出力は私たちのエンティティであり、JSON入力からのデータが入力されています。

Movie[imdbId=tt0472043, director=null, actors=[ActorJackson
 [imdbId=nm2199632, dateOfBirth=Tue Sep 21 04:00:00 PDT 1982,
  filmography=[Apocalypto, Beatdown, Wind Walkers]]]]----

単純なシリアライザの場合と同様に、

**  JSON入力名はJavaエンティティ名と一致している必要があります。

それらは__null、__に設定されています
**  __dateOfBirth__フィールドはデフォルトのJackson日付で翻訳されました

タイムゾーンを無視します。

====  **  7.2. カスタム逆シリアル化**

カスタムのデシリアライザを使用すると、標準のデシリアライザの動作を変更できます。

この場合、日付に__dateOfBirthの正しいタイムゾーンを反映させたいので、__FormMasterにDateFormatterを追加します。

[source,java,gutter:,true]

String jsonInput = “{\”imdbId\”:\”tt0472043\”,\”director\”:\”Mel Gibson\”,
\”actors\”:[{\”imdbId\”:\”nm2199632\”,\”dateOfBirth\”:\”1982-09-21T12:00:00+01:00\”,
\”filmography\”:[\”Apocalypto\”,\”Beatdown\”,\”Wind Walkers\”]}]}”;

ObjectMapper mapper = new ObjectMapper();
DateFormat df = new SimpleDateFormat(“yyyy-MM-dd’T’HH:mm:ss”);
mapper.setDateFormat(df);

Movie movie = mapper.readValue(jsonInput, Movie.class);
movie.toString();

出力は、日付付きの正しいタイムゾーンを反映しています。

[source,java,gutter:,true]

Movie[imdbId=tt0472043, director=Mel Gibson, actors=[ActorJackson
[imdbId=nm2199632, dateOfBirth=Tue Sep 21 12:00:00 PDT 1982,
filmography=[Apocalypto, Beatdown, Wind Walkers]]]]—-

この解決策は清潔で簡単です。

あるいは、

ActorJackson

クラスのカスタムデシリアライザーを作成し、このモジュールを

ObjectMapper

に登録し、

ActorJackson

エンティティの

@ JsonDeserialize

アノテーションを使用して日付をデシリアライズすることもできます。

このアプローチの不利な点はエンティティを変更する必要があることです。これは入力エンティティクラスにアクセスできない場合には理想的ではないかもしれません。


8結論

GsonとJacksonはどちらもJSONデータをシリアライズ/デシリアライズするための優れたオプションであり、使いやすく、よく文書化されています。

Gsonの利点:

  • 単純な場合は

    toJson

    /

    fromJson

    の単純さ

  • 逆シリアル化のために、Javaエンティティにアクセスする必要はありません。

ジャクソンの利点:

  • すべてのJAX-RS(Jersey、Apache CXF、RESTEasy、Restlet)に組み込まれています。

春のフレームワーク
** 広範な注釈のサポート

GitHubにhttps://github.com/eugenp/tutorials/tree/master/gson[Gson]とhttps://github.com/eugenp/tutorials/tree/master/jackson[Jackson]のコードがあります。