2013-01-10 37 views
2

傑克遜的多態序列化/反序列化能力真的很酷,或者如果我能想出如何將其應用於我手邊的問題。 http://programmerbruce.blogspot.com/2011/05/deserialize-json-with-jackson-into.html有一篇不錯的文章,我無法適應我簡化的問題。Jackson 2.1.2多態反序列化拋出JsonMappingException。爲什麼?

簡而言之,我能夠得到Jackson 2.1.2將一個類層次結構序列化成帶有類型信息的JSON字符串。然而,我無法讓Jackson 2.1.2將該JSON字符串反序列化爲我的類層次結構。下面是一個揭示這個問題的單元測試。

類層次結構足夠簡單;只有兩個直接子類的基類。此外,JSON輸出似乎尊重我的傑克遜@JsonTypeInfo和mapper.writeValueAsString

{"type":"dog","name":"King","breed":"Collie"} 

但我對mapper.readValue(jsonOfKing,Animal.class)調用產生一個可信的字符串蹤跡......

FAILED: testJacksonSerializeDeserialize 
com.fasterxml.jackson.databind.JsonMappingException: No suitable constructor found for type [simple type, class org.rekdev.fasterjacksonwtf.PolymorphismTests$Dog]: can not instantiate from JSON object (need to add/enable type information?) 
at [Source: [email protected]; line: 1, column: 14] 
    at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:164) 
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObjectUsingNonDefault(BeanDeserializer.java:400) 
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:289) 
.... 

這是我的單元測試。

import org.testng.annotations.*; 
import static org.testng.Assert.*; 
import com.fasterxml.jackson.annotation.*; 
import com.fasterxml.jackson.annotation.JsonSubTypes.Type; 
import com.fasterxml.jackson.databind.*; 

public class PolymorphismTests { 
    @Test 
    public void testJacksonSerializeDeserialize() throws Exception { 
     ObjectMapper mapper = new ObjectMapper(); 

     Animal king = new Dog(); 
     king.name = "King"; 
     ((Dog) king).breed = "Collie"; 
     String jsonOfKing = mapper.writeValueAsString(king); 
     // JsonMappingException right here! 
     Animal actualKing = mapper.readValue(jsonOfKing, Animal.class); 
     assertEquals(king, actualKing); 

    } 

    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type") 
    @JsonSubTypes({ @Type(value = Cat.class, name = "cat"), @Type(value = Dog.class, name = "dog") }) 
    abstract class Animal { 
     public String name; 

     @Override 
     public abstract boolean equals(Object obj); 

     @Override 
     public abstract int hashCode(); 
    } 

    class Dog extends Animal { 
     public String breed; 

     @Override 
     public boolean equals(Object obj) { 
      if (this == obj) { 
       return true; 
      } 
      if (obj == null) { 
       return false; 
      } 
      if (getClass() != obj.getClass()) { 
       return false; 
      } 
      final Dog that = (Dog) obj; 
      boolean equals = name.equals(that.name) && breed.equals(that.breed); 
      return equals; 
     } 

     @Override 
     public int hashCode() { 
      int hashCode = name.hashCode() + breed.hashCode(); 
      return hashCode; 
     } 
    } 

    class Cat extends Animal { 
     public String favoriteToy; 

     @Override 
     public boolean equals(Object obj) { 
      if (this == obj) { 
       return true; 
      } 
      if (obj == null) { 
       return false; 
      } 
      if (getClass() != obj.getClass()) { 
       return false; 
      } 
      final Cat that = (Cat) obj; 
      boolean equals = name.equals(that.name) && favoriteToy.equals(that.favoriteToy); 
      return equals; 
     } 

     @Override 
     public int hashCode() { 
      int hashCode = name.hashCode() + favoriteToy.hashCode(); 
      return hashCode; 
     } 
    } 
} 

爲什麼不ObjectMapper讓我readValue過程中由ObjectMapper.writeValue產生的JSON()?

+0

也許這裏有一個線索:http://stackoverflow.com/questions/11798394/polymorphism-in-jackson-annotations-jsontypeinfo-usage。 「最不驚奇的原則」這種努力並非如此。 –

+0

沒有。並不那麼簡單。按下。 –

+1

乍一看,我看到你在使用內部類的定義。這與我發佈的例子不同。 –

回答

2

讓你的內部類的靜態,如:

static class Dog extends Animal { ... } 

否則事情將無法正常工作(因爲非靜態內部類需要所謂的「隱性這個」說法指封閉類的實例)。

+0

那就是它!試圖隔離問題,導致了問題。現在,我正在努力讓這些孩子永遠不變。謝謝。 –

+0

好。不可變的組合(使用'@ JsonCreator'),多態類型可能會非常棘手;但至少你可以隱藏setters(使用私人領域或setter) – StaxMan

相關問題