web-dev-qa-db-ja.com

ジャクソンは余分なフィールドをマップとしてデシリアライズします

私はJSONオブジェクトの不明なフィールドを、pojoのメンバーであるマップのエントリーとしてデシリアライズしようとしています。

たとえば、json

{
  "knownField" : 5,
  "unknownField1" : "926f7c2f-1ae2-426b-9f36-4ba042334b68",
  "unknownField2" : "ed51e59d-a551-4cdc-be69-7d337162b691"
}

とポージョ

class myObject{
  int knownField;
  Map<String, UUID> unknownFields;
  // getters/setters whatever
}

ジャクソンでこれを構成する方法はありますか?そうでない場合、それを行うためにStdDeserializerを書き込む効果的な方法はありますか(unknownFieldsの値はより複雑ですがよく知られている一貫した型であると想定してください)?

20
kag0

この目的にぴったり合う機能と注釈があります。

私はテストし、あなたの例のようにUUIDで動作します:

class MyUUIDClass {
    public int knownField;

    Map<String, UUID> unknownFields = new HashMap<>();

    // Capture all other fields that Jackson do not match other members
    @JsonAnyGetter
    public Map<String, UUID> otherFields() {
        return unknownFields;
    }

    @JsonAnySetter
    public void setOtherField(String name, UUID value) {
        unknownFields.put(name, value);
    }
}

そしてそれはこのように機能します:

    MyUUIDClass deserialized = objectMapper.readValue("{" +
            "\"knownField\": 1," +
            "\"foo\": \"9cfc64e0-9fed-492e-a7a1-ed2350debd95\"" +
            "}", MyUUIDClass.class);

また、文字列などのより一般的な型も機能します。

class MyClass {
    public int knownField;

    Map<String, String> unknownFields = new HashMap<>();

    // Capture all other fields that Jackson do not match other members
    @JsonAnyGetter
    public Map<String, String> otherFields() {
        return unknownFields;
    }

    @JsonAnySetter
    public void setOtherField(String name, String value) {
        unknownFields.put(name, value);
    }
}

私は最初にこのブログ投稿でこの機能を見つけました )。

30
Peter Lamberg

あなたはこのような何かをカスタムデシリアライザを書く必要があります

_class CustomDeserializer extends StdDeserializer<MyObject>{

    public CustomDeserializer(Class<MyObject> t) {
        super(t);
    }

    @Override
    public MyObject deserialize(JsonParser parser, DeserializationContext context)
            throws IOException, JsonProcessingException {
        int knownField=0;
        Map<String, UUID> unknownFields = new HashMap<String, UUID>();

        JsonToken currentToken = null;
      while ((currentToken = parser.nextValue()) != null) {
          switch (currentToken) {
              case VALUE_NUMBER_INT:
                  if (parser.getCurrentName().equals("knownField")) {
                      knownField = parser.getIntValue();
                  }
                  break;
              case VALUE_STRING:
                  if (parser.getCurrentName().startsWith("unknownField")){
                      unknownFields.put(parser.getCurrentName(),UUID.fromString(parser.getValueAsString()));
                  }
                  break;
              default:
                  break;
          }
      }
      return new MyObject(knownField,unknownFields);
    }
}
_

次に、次のようにカスタムデシリアライザを設定します。

_ObjectMapper mapper = new ObjectMapper();
        SimpleModule mod = new SimpleModule("TestModule");
        mod.addDeserializer(MyObject.class, new CustomDeserializer(MyObject.class));
        mapper.registerModule(mod);
        MyObject myObj = mapper.readValue(contents, MyObject.class);
_

編集:_START_OBJECT_トークンを押すと、複雑なオブジェクトを逆シリアル化できます。そしてDeserializationContext.readValue(JsonParser, Class<MyObject>)を使用してMyObjectをデシリアライズします

0
ravthiru