【Java】JacksonのObjectMapperのreadValueメソッドで例外が発生する。。。対処法は?

JSONからオブジェクトへの変換時にオブジェクトに存在しない項目がJSONデータに含まれていると例外が発生することがあります

5種の対策法をご紹介します!


1. 単純にオブジェクトに対応するフィールドを追加する

JSONデータに存在するがオブジェクトにない項目がある場合、その項目に対応するフィールドをオブジェクトに追加します
この新しいフィールドは変換時には無視されるか、適切なデフォルト値がセットされるようにします

public class MyObject {
    private String name;
    private int age;

    // 新しいフィールド
    private String additionalField;

    // getterとsetterを追加
    public String getAdditionalField() {
        return additionalField;
    }

    public void setAdditionalField(String additionalField) {
        this.additionalField = additionalField;
    }

    // 他のフィールドのgetterとsetterは省略
}

2. オプションを設定して例外を無視する

ObjectMapperの設定を変更して、JSONデータに存在しないフィールドが無視されるようにします

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

try {
    MyObject myObject = objectMapper.readValue(jsonString, MyObject.class);
    // JSONデータの変換が成功した場合の処理
} catch (IOException e) {
    // JSONデータの変換に失敗した場合の処理
}

configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) を使うと、未知のプロパティがJSONデータに含まれていても例外が発生せず、変換が成功します

ただし、注意が必要!
この設定は意図しないデータが無視される可能性があります。。。


3. カスタムデシリアライザを実装する

カスタムのJsonDeserializerを実装して、JSONデータをオブジェクトに変換する際に制御を追加します
これにより、不明なプロパティを処理する方法を完全にカスタマイズできます

public class MyObjectDeserializer extends JsonDeserializer<MyObject> {
    @Override
    public MyObject deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        ObjectNode node = jsonParser.readValueAsTree();
        String name = node.get("name").asText();
        int age = node.get("age").asInt();
        // 追加のフィールドを取得
        String additionalField = null;
        if (node.has("additionalField")) {
            additionalField = node.get("additionalField").asText();
        }

        MyObject myObject = new MyObject();
        myObject.setName(name);
        myObject.setAge(age);
        myObject.setAdditionalField(additionalField);

        return myObject;
    }
}

そして、ObjectMapperでこのカスタムデシリアライザを使用します

ObjectMapper objectMapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(MyObject.class, new MyObjectDeserializer());
objectMapper.registerModule(module);

MyObject myObject = objectMapper.readValue(jsonString, MyObject.class);

ぜひお試しください!


4. @JsonIgnorePropertiesアノテーションを使用する

クラスレベルで@JsonIgnorePropertiesアノテーションを使用して、不明なプロパティを無視するように指定できます
このアノテーションをクラスに付けることで、JSONに存在するがクラスに定義されていないプロパティを無視します

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown = true)
public class MyObject {
    private String name;
    private int age;
    
    // getterとsetterを追加
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

5. JsonNodeを使って柔軟に処理する

一度、JsonNodeにパースしてから必要なフィールドを抽出する方法です

柔軟にデータを扱うことができます

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

ObjectMapper objectMapper = new ObjectMapper();
try {
    JsonNode rootNode = objectMapper.readTree(jsonString);
    String name = rootNode.path("name").asText();
    int age = rootNode.path("age").asInt();
    
    MyObject myObject = new MyObject();
    myObject.setName(name);
    myObject.setAge(age);
    
    // JSONデータの変換が成功した場合の処理
} catch (IOException e) {
    // JSONデータの変換に失敗した場合の処理
}

是非フォローしてください

最新の情報をお伝えします