2015-02-06 56 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);