2013-03-25 209 views
4

我一直在嘗試應用http://programmerbruce.blogspot.com/2011/05/deserialize-json-with-jackson-into.html)\,並將其應用於我一直在努力的方面。雖然它對JSON結構中所謂的「外部」元素非常有用,但我遇到了一個令人沮喪的問題,那就是沒有太多的文檔。傑克遜JSON多態性

首先,我的代碼有點像下面這樣:

interface Parameters { 
    // Couple random properties -- no problem here 

    SubTypeParameters getSubTypeParameters(); // where SubTypeParameters are polymorphic 
    void setSubTypeParameters(SubTypeParameters value); 
} 

@JsonSubTypes({ 
    @JsonSubTypes.Type(name = "a", value = ASubTypeParameters.class), 
    @JsonSubTypes.Type(name = "b", value = BSubTypeParameters.class) 
}) 
interface SubTypeParameters { 
    String getValue(); 
    void setValue(String value); 
} 

@JsonTypeName(value = "a") 
class ASubTypeParameters implements SubTypeParameters { 
    // getter/setter implemented 
} 

@JsonTypeName(value = "b") 
class BSubTypeParameters implements SubTypeParameters { 
    // getter/setter implemented 
} 

我試圖做的是落實在鏈接的博客帖子6號選項,以便JSON會出現如下內容(公告沒有 '類型' 指定元件 - 它基於關閉上下文):

{ 
    // other properties corresponding to the Parameters object 
    "a": { 
     "value": "value for a" 
    } 
} 

{ 
    // other properties corresponding to the Parameters object 
    "b": { 
     "value": "value for b" 
    } 
} 

我試圖避免的是向JSON對象中引入另一個「類型」變量。相反,我更願意使用提供給上述任何一個JSON示例的上下文來知道我應該基於「a」或「b」的存在構建一個ASubTypeParameters或BSubTypeParameters對象。

的有趣的事情是,參數類/對象也多態,所以我已經註冊了自己的自定義解串器類如下所示:

ObjectMapper mapper = new ObjectMapper(); 
StdDeserializer<Parameters> parameterDeserializer = new ParameterDeserializer(); 
SimpleModule module = new SimpleModule (...); // simplifying this--no problem here 
module.addDeserializer(Parameters.class, parameterDeserializer); 
mapper.registerModule(module); 
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); 

然而,當上述解串器試圖反序列化任一以上的JSON示例,它會到達它試圖反序列化「a」或「b」的部分,並指示它不知道如何處理這些屬性(如果我移除未知屬性行上的失敗,則爲UnrecognizedPropretyException)。我的問題真的歸結爲:我錯過了什麼(註釋或其他)?

我也嘗試添加:

mapper.registerSubtypes(ASubTypeParameters.class, BSubTypeParameters.class) 

以及

mapper.registerSubtypes(
    new NamedType(ASubTypeParameters.class, "a"), 
    new NamedType(BSubTypeParameters.class, "b") 
); 

無濟於事。

我知道我越來越接近了,我的猜測是我需要編寫某種自定義子類型處理程序,但文檔似乎缺少我想要做的事情(特別是當您反序列化也包含多態元素的多態類型/類)。

回答

2

使用Jackson,您可以配置使用以下注釋將類型信息存儲爲單個字段的名稱:@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.WRAPPER_OBJECT)。結果應該看起來像你的JSON例子。

我稍微修改代碼來證明它:

public class JacksonPolymorphic2 { 
    @JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.WRAPPER_OBJECT) 
    @JsonSubTypes({ 
      @JsonSubTypes.Type(name = "a", value = ASubTypeParameters.class), 
      @JsonSubTypes.Type(name = "b", value = BSubTypeParameters.class) 
    }) 
    interface SubTypeParameters { 
     String getValue(); 
     void setValue(String value); 
    } 

    @JsonTypeName(value = "a") 
    static class ASubTypeParameters implements SubTypeParameters { 
     ASubTypeParameters(String value) { 
      this.value = value; 
     } 

     private String value; 
     @Override 
     public String getValue() { 
      return value; 
     } 

     @Override 
     public void setValue(String value) { 
      this.value = value; 
     } 
    } 

    @JsonTypeName(value = "b") 
    static class BSubTypeParameters implements SubTypeParameters { 
     BSubTypeParameters(String value) { 
      this.value = value; 
     } 

     private String value; 
     @Override 
     public String getValue() { 
      return value; 
     } 

     @Override 
     public void setValue(String value) { 
      this.value = value; 
     } 
    } 

    public static void main(String[] args) throws JsonProcessingException { 
     ASubTypeParameters a = new ASubTypeParameters("aType"); 
     BSubTypeParameters b = new BSubTypeParameters("bType"); 
     List<? super SubTypeParameters> list = new ArrayList<>(); 
     list.add(a); 
     list.add(b); 

     ObjectMapper mapper = new ObjectMapper(); 
     System.out.printf(mapper 
       .writerWithType(new TypeReference<List<SubTypeParameters>>() {}) 
       .withDefaultPrettyPrinter() 
       .writeValueAsString(list)); 
    } 
} 

輸出:

[ { 
    "a" : { 
    "value" : "aType" 
    } 
}, { 
    "b" : { 
    "value" : "bType" 
    } 
} ]