1. 概要

このクイックチュートリアルでは、Jackson2を使用してカスタムデシリアライザーを使用してJSONをデシリアライズする方法を説明します。

ジャクソン2でできる他のクールなことをさらに深く掘り下げるには、メインのジャクソンチュートリアルに進んでください。

2. 標準の逆シリアル化

2つのエンティティを定義することから始めて、JacksonがカスタマイズなしでJSON表現をこれらのエンティティに逆シリアル化する方法を見てみましょう。

public class User {
    public int id;
    public String name;
}
public class Item {
    public int id;
    public String itemName;
    public User owner;
}

次に、逆シリアル化するJSON表現を定義しましょう。

{
    "id": 1,
    "itemName": "theItem",
    "owner": {
        "id": 2,
        "name": "theUser"
    }
}

そして最後に、このJSONをJavaエンティティにアンマーシャリングしましょう。

Item itemWithOwner = new ObjectMapper().readValue(json, Item.class);

3. ObjectMapperのカスタムデシリアライザー

前の例では、JSON表現はJavaエンティティと完全に一致していました。

次に、JSONを単純化します。

{
    "id": 1,
    "itemName": "theItem",
    "createdBy": 2
}

これをまったく同じエンティティにアンマーシャリングする場合、デフォルトでは、これはもちろん失敗します。

com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: 
Unrecognized field "createdBy" (class org.baeldung.jackson.dtos.Item), 
not marked as ignorable (3 known properties: "id", "owner", "itemName"])
 at [Source: java.io.StringReader@53c7a917; line: 1, column: 43] 
 (through reference chain: org.baeldung.jackson.dtos.Item["createdBy"])

これを解決するには、カスタムデシリアライザーを使用して独自のデシリアライズを実行します。

public class ItemDeserializer extends StdDeserializer<Item> { 

    public ItemDeserializer() { 
        this(null); 
    } 

    public ItemDeserializer(Class<?> vc) { 
        super(vc); 
    }

    @Override
    public Item deserialize(JsonParser jp, DeserializationContext ctxt) 
      throws IOException, JsonProcessingException {
        JsonNode node = jp.getCodec().readTree(jp);
        int id = (Integer) ((IntNode) node.get("id")).numberValue();
        String itemName = node.get("itemName").asText();
        int userId = (Integer) ((IntNode) node.get("createdBy")).numberValue();

        return new Item(id, itemName, new User(userId, null));
    }
}

ご覧のとおり、デシリアライザーはJSONの標準的なJackson表現であるJsonNodeで動作しています。 入力JSONがJsonNodeとして表されると、そこから関連情報を抽出して、独自のItemエンティティを構築できます。

簡単に言うと、このカスタムデシリアライザー登録し、JSONを通常どおりデシリアライズする必要があります。

ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(Item.class, new ItemDeserializer());
mapper.registerModule(module);

Item readValue = mapper.readValue(json, Item.class);

4. クラスのカスタムデシリアライザー

または、デシリアライザーをクラスに直接登録することもできます。

@JsonDeserialize(using = ItemDeserializer.class)
public class Item {
    ...
}

デシリアライザーがクラスレベルで定義されているため、 ObjectMapper に登録する必要はありません—デフォルトのマッパーは正常に機能します。

Item itemWithOwner = new ObjectMapper().readValue(json, Item.class);

このタイプのクラスごとの構成は、構成する生のObjectMapperに直接アクセスできない場合に非常に役立ちます。

5. 結論

この記事では、Jackson 2を活用して非標準のJSON入力を読み取る方法と、マッピングを完全に制御してその入力を任意のJavaエンティティグラフにマッピングする方法を示しました。

これらすべての例とコードスニペットの実装は、GitHubにあります。 これはMavenベースのプロジェクトなので、そのままインポートして実行するのは簡単です。