複数のJSONフィールドを単一のJavaフィールドにマッピングする

1. 概要

このチュートリアルでは、JacksonとGsonの両方を使用して、異なるJSONフィールドを単一のJavaフィールドにマッピングする方法を説明します。

2. Mavenの依存関係

https://search.maven.org/search?q=a:jackson-databind%20AND%20g:com.fasterxml.jackson.core[Jackson]およびhttps://search.maven.org/を使用するにはsearch?q = a:gson%20AND%20g:com.google.code.gson [Gson]ライブラリでは、次の依存関係をPOMに追加する必要があります。
<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.5</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.8</version>
    <scope>test</scope>
</dependency>

3. サンプルJSON

さまざまな場所の天気の詳細をJavaアプリケーションに取得したいと考えてみましょう。 気象データをJSONドキュメントとして公開するWebサイトがいくつか見つかりました。 ただし、それらはわずかに異なる形式を使用します。
{
    "location": "London",
    "temp": 15,
    "weather": "Cloudy"
}
And:
{
    "place": "Lisbon",
    "temperature": 35,
    "outlook": "Sunny"
}
これらの両方の形式を、_Weather_という名前の同じJavaクラスにデシリアライズします。
public class Weather {
    private String location;
    private int temp;
    private String outlook;
}
それでは、JacksonとGsonの両方のライブラリを使用してこれを実現する方法を見てみましょう。

4. ジャクソンを使用して

*これを実現するために、Jacksonの_ @ JsonProperty_および_ @ JsonAlias_アノテーションを使用します。 これらにより、複数のJSONプロパティを同じJavaフィールドにマッピングできます*。
最初に、_ @ JsonProperty_アノテーションを使用して、JacksonがマッピングするJSONフィールドの名前を知るようにします。 _ @ JsonProperty_アノテーションの値は、逆シリアル化とシリアル化の両方に使用されます。
その後、_ @ JsonAlias_アノテーションを使用できます。 その結果、Jacksonは、JavaフィールドにマップされているJSONドキュメント内の他のフィールドの名前を認識します。 _ @ JsonAlias_アノテーションの値は、逆シリアル化にのみ使用されます。
@JsonProperty("location")
@JsonAlias("place")
private String location;
@JsonProperty("temp")
@JsonAlias("temperature")
private int temp;

@JsonProperty("outlook")
@JsonAlias("weather")
private String outlook;
注釈を追加したので、Jacksonの_ObjectMapper_を使用して、_Weather_クラスを使用してJavaオブジェクトを作成しましょう。
@Test
public void givenTwoJsonFormats_whenDeserialized_thenWeatherObjectsCreated() throws Exception {

    ObjectMapper mapper = new ObjectMapper();

    Weather weather = mapper.readValue("{\n"
      + "  \"location\": \"London\",\n"
      + "  \"temp\": 15,\n"
      + "  \"weather\": \"Cloudy\"\n"
      + "}", Weather.class);

    assertEquals("London", weather.getLocation());
    assertEquals("Cloudy", weather.getOutlook());
    assertEquals(15, weather.getTemp());

    weather = mapper.readValue("{\n"
      + "  \"place\": \"Lisbon\",\n"
      + "  \"temperature\": 35,\n"
      + "  \"outlook\": \"Sunny\"\n"
      + "}", Weather.class);

    assertEquals("Lisbon", weather.getLocation());
    assertEquals("Sunny", weather.getOutlook());
    assertEquals(35, weather.getTemp());
}

5. Gsonを使用する

*今、Gsonでも同じことを試してみましょう。 _ @ SerializedName_アノテーションで_value_パラメーターと_alternate_パラメーターを使用する必要があります。*
1つ目はデフォルトとして使用され、2つ目はマップするJSONフィールドの代替名を示すために使用されます。
@SerializedName(value="location", alternate="place")
private String location;
@SerializedName(value="temp", alternate="temperature")
private int temp;

@SerializedName(value="outlook", alternate="weather")
private String outlook;
注釈を追加したので、例をテストしてみましょう。
@Test
public void givenTwoJsonFormats_whenDeserialized_thenWeatherObjectsCreated() throws Exception {

    Gson gson = new GsonBuilder().create();
    Weather weather = gson.fromJson("{\n"
      + "  \"location\": \"London\",\n"
      + "  \"temp\": 15,\n"
      + "  \"weather\": \"Cloudy\"\n"
      + "}", Weather.class);

    assertEquals("London", weather.getLocation());
    assertEquals("Cloudy", weather.getOutlook());
    assertEquals(15, weather.getTemp());

    weather = gson.fromJson("{\n"
      + "  \"place\": \"Lisbon\",\n"
      + "  \"temperature\": 35,\n"
      + "  \"outlook\": \"Sunny\"\n"
      + "}", Weather.class);

    assertEquals("Lisbon", weather.getLocation());
    assertEquals("Sunny", weather.getOutlook());
    assertEquals(35, weather.getTemp());

}

6. 結論

Jacksonの_ @ JsonAlias_またはGsonの_alternate_パラメーターを使用することで、異なるJSON形式を同じJavaオブジェクトに簡単に変換できることがわかりました。
サンプルはhttps://github.com/eugenp/tutorials/tree/master/jackson-2[Jackson] httpsおよびhttps://github.com/eugenp/tutorials/tree/master/gson [ GitHubでのGsonプロジェクト]。