2015-02-06 150 views
0

我已通过在基类中添加注释来启用多形态序列化支持。我能够成功地对一个单独的对象进行序列化,并且将类型信息作为序列化数据的一部分写入。但是,如果我将对象存储在列表中并将其序列化,则不会发生同样的情况。多形阵列失败的序列化

看来这个问题是固定在1.6.3(http://jira.codehaus.org/browse/JACKSON-362

我使用杰克逊2.3.2,仍然面临的问题。

有人知道如何解决这个问题吗?

代码:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY,property = "type") 
@JsonSubTypes({@Type(value = Derived.class, name = "derived")}) 
public abstract class Base { 

} 

public class Derived extends Base { 

    private String field; 

    public String getField() { 
     return field; 
    } 

    public void setField(String field) { 
     this.field = field; 
    } 

} 

public class Test { 

    public static void main(String[] args) throws JsonProcessingException { 
     ObjectMapper mapper = new ObjectMapper(); 
     Derived d = new Derived(); 
     d.setField("Name"); 
     Base b = d; 
     System.out.println(mapper.writeValueAsString(b)); 
     List<Base> list = new ArrayList<Base>(); 
     list.add(d); 
     System.out.println(mapper.writeValueAsString(list)); 
    } 
} 

输出:
{ “类型”: “导出”, “字段”: “名称”}
[{ “字段”: “名称”}]

谢谢,
普利文

+1

你当然可以进行序列化和反序列化多态与杰克逊对象的列表。你可以在你序列化/试图反序列化这些对象的地方分享你的代码吗? – wdf 2015-02-06 16:07:57

回答

1

答案是https://github.com/FasterXML/jackson-databind/issues/699

这是由于Java类型擦除:当序列化一个List时,所有Jackson看到的类型都是List(大致相当于List)。由于类型Object没有多态类型信息(注解),所以不会写任何东西。 所以这不是杰克逊的一个bug,而是Java Type Erasure的一个不幸的功能。 它不适用于数组,因为它们保留元素类型信息(数组不是通用的;不同类型的数组是不同的类,而通用类型大部分是编译时语法糖)。

主要有三种方式来解决这个问题:

pass full generic type using TypeReference (ObjectMapper has method like mapper.writerFor(new TypeReference<List<Base>>() { }).writeValue(....) 
Sub-class List to something like public class BaseList extends ArrayList<Base>() { }, and pass that: this type WILL retain type information 
Avoid using root-level List and Maps 

我个人建议这样做(3),因为这避免了类型擦除所有相关的问题。 在我看来,JSON根值应该始终是一个JSON对象,通常是序列化到/从POJO。

然而,方法(2)将工作,这是大多数用户所做的工作。它需要使用额外的辅助类。 (1)可能或不可以工作;问题是强制类型信息也会影响实际值序列化。因此,虽然它会添加类型ID,但可能会导致某些属性未被序列化。

1

这个问题可以通过使用数组来解决,而不是列表,(因为名单进行类型擦除):

例如,您上面的测试情况可以写成:

public class Test { 

    public static void main(String[] args) throws JsonProcessingException { 
     ObjectMapper mapper = new ObjectMapper(); 
     Derived d = new Derived(); 
     d.setField("Name"); 
     Base b = d; 
     System.out.println(mapper.writeValueAsString(b)); 
     List<Base> list = new ArrayList<Base>(); 
     list.add(d); 
     System.out.println(mapper.writeValueAsString(
         list.toArray(new Base[list.size]) // <--This Part 
      )); 
    } 
} 
0

我与对象数组相同的问题。 Object []不包含类型信息,但单个对象可以。杰克逊无法自动处理这一点令人遗憾。

两种可能的解决方案: 1。类型数组序列化工作得很好:

Base[] myArray = Base[]{d}; 
mapper.writeValueAsString(myArray) 

这实际上会产生预期的结果作为基础[]的类型信息。

  1. 我解决了我的问题与自定义序列化程序。

串行:

public class ObjectArraySerializer extends StdSerializer<Object[]> { 
    public ObjectArraySerializer(final Class<Object[]> vc) { 
    super(vc); 
    } 

    @Override 
    public void serialize(
     final Object[] data, 
     final JsonGenerator gen, 
     final SerializerProvider provider) throws IOException { 
    gen.writeStartArray(); 
    for (Object obj : data) { 
     gen.writeObject(obj); 
    } 
    gen.writeEndArray(); 
    } 
} 

ObjectMapper配置:

ObjectMapper objectMapper = new ObjectMapper(); 
SimpleModule module = new SimpleModule(); 
module.addSerializer(
    Object[].class, 
    new ObjectArraySerializer(Object[].class)); 
objectMapper.registerModule(module);