2016-08-25 4 views
3

私は、pojoのメンバーであるマップのエントリとしてJSONオブジェクトの未知のフィールドを逆シリアル化したいと考えています。Jacksonはマップとして余分なフィールドを非直列化します

例えば、JSON

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

とPOJO

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

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

答えて

5

この目的にちょうど適合する機能と注釈があります。

私がテストし、それはあなたの例のようにの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); 
    } 
} 

I found this feature in this blog post first)。

+0

完璧に見えます。前回の回答よりも明らかに好ましいと言えば、答えとしてマークしています。 – kag0

0

あなたが

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); 

編集を次のように続いて、カスタムデシリアライザを設定し、この

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); 
    } 
} 

のようないくつかのことデシリアライザカスタム記述する必要があります:あなたはSTART_OBJECTトークンを打ったときあなたはどんな複雑なオブジェクトをデシリアライズすることができます。 DeserializationContext.readValue(JsonParser, Class<MyObject>)を使用してMyObjectを逆シリアル化する

+0

私の要件「unknownFieldsの値がより複雑でよく知られている一貫したタイプであることを前提とする」を解決する方法がありますか?つまり値がオブジェクトである場合、 'UUID.fromString'は適切ではなく、より複雑な値の直列化が必要です。 – kag0

+0

複雑なオブジェクトを扱えるようにする必要があります。START_OBJECTとEND_OBJECTトークンを使ってオブジェクトを検出し、必要に応じて逆シリアル化してください。 – ravthiru

+0

掘り起こす私は、 'START_OBJECT'の場合、私が'MyObject'を逆シリアル化するために' DeserializationContext.readValue(JsonParser、Class ) 'を使うべきです(私のために働いています)。それをあなたの答えに加えたいなら、私は先に進んでそれを受け入れます。 – kag0

関連する問題