2013-03-25 160 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" 
    } 
} ]