2013-01-10 36 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

相关问题