【问题标题】:JSON Jackson - exception when serializing a polymorphic class with custom serializerJSON Jackson - 使用自定义序列化程序序列化多态类时出现异常
【发布时间】:2015-03-08 16:29:06
【问题描述】:

我目前正在将一些代码从 Jackson 1.x 迁移到 Jackson 2.5 json 映射器,并且出现了一个 1.x 中不存在的问题。

这是设置(见下面的代码):

  • 接口IPet
  • 类Dog实现IPet
  • IPet 使用 @JsonTypeInfo 和 @JsonSubTypes 注释
  • 类 Human 具有使用 @JsonSerialize(using=CustomPetSerializer.class) 注释的 IPet 类型的属性

问题: 如果我序列化 Dog 的一个实例,它会按预期工作(Jackson 也将类型信息添加到 json 字符串中)。 但是,当我序列化 Human 类的实例时,会抛出异常:

com.fasterxml.jackson.databind.JsonMappingException:类型 id 处理 com.pet.Dog 类型未实现(通过引用链: com.Human["pet"])

未调用 CustomPetSerializer 类的 serialize(...) 方法(使用断点进行测试)。

代码:

IPet 实施:

@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.PROPERTY, property="type")
@JsonSubTypes({
     @JsonSubTypes.Type(value=Dog.class,    name="dog")
    //,@JsonSubTypes.Type(value=Cat.class,  name="cat")
    //more subtypes here...
})
public interface IPet
{
    public Long getId();
    public String getPetMakes();
}

狗实现:

public class Dog implements IPet
{
    @Override
    public String getPetMakes()
    {
        return "Wuff!";
    }

    @Override
    public Long getId()
    {
        return 777L;
    }
}

养狗的人:

public class Human
{
    private IPet pet = new Dog();

    @JsonSerialize(using=CustomPetSerializer.class)
    public IPet getPet()
    {
        return pet;
    }
}

CustomPetSerializer 实现:

public class CustomPetSerializer extends JsonSerializer<IPet>
{
    @Override
    public void serialize(IPet value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException
    {
        if(value != null && value.getId() != null)
        {
            Map<String,Object> style = new HashMap<String,Object>();
            style.put("age", "7");
            gen.writeObject(style);
        }
    }
}

JUnit 测试方法:

@Test
public void testPet() throws JsonProcessingException
{
    ObjectMapper mapper = new ObjectMapper();

    Human human = new Human();

    //works as expcected
    String json = mapper.writeValueAsString(human.getPet());
    Assert.assertNotNull(json);
    Assert.assertTrue(json.equals("{\"type\":\"dog\",\"id\":777,\"petMakes\":\"Wuff!\"}"));

    //throws exception: Type id handling not implemented for type com.pet.Dog (through reference chain: com.Human["pet"])
    json = mapper.writeValueAsString(human);    //exception is thrown here
    Assert.assertNotNull(json);
    Assert.assertTrue(json.contains("\"age\":\"7\""));
}

【问题讨论】:

    标签: java json jackson


    【解决方案1】:

    自从 Jackson 2.9 writeTypePrefixForObject()writeTypeSuffixForObject() 已被弃用(我不清楚为什么)。在新方法下,它现在似乎是:

    @Override
    public void serializeWithType(IPet value, JsonGenerator gen, 
            SerializerProvider provider, TypeSerializer typeSer) 
            throws IOException, JsonProcessingException {
    
      WritableTypeId typeId = typeSer.typeId(value, START_OBJECT);
      typeSer.writeTypePrefix(gen, typeId);
      serialize(value, gen, provider); // call your customized serialize method
      typeSer.writeTypeSuffix(gen, typeId);
    }
    

    所以现在多了一行,所以不知道为什么它向前迈了一步,也许重用typeId 对象更有效。

    来源: Jackson 的ObjectNode 课程目前是硕士。不是最好的来源,但看不到任何升级文档解释要做什么。

    【讨论】:

    • 最后一行不应该是END_OBJECT吗?所以没有重复使用typeId
    • @mat3e,我不这么认为,因为com.fasterxml.jackson.databind.ser.std.BeanSerializerBase#serializeWithType 也这样做。
    【解决方案2】:

    您还需要在 CustomPetSerializer 内部覆盖 serializeWithType,因为 IPet 是多态的。这也是不调用serialize 的原因。检查this related SO question,它详细解释了何时调用serializeWithType。例如,您的 serializeWithType 实现可能如下所示:

    @Override
    public void serializeWithType(IPet value, JsonGenerator gen, 
            SerializerProvider provider, TypeSerializer typeSer) 
            throws IOException, JsonProcessingException {
    
      typeSer.writeTypePrefixForObject(value, gen);
      serialize(value, gen, provider); // call your customized serialize method
      typeSer.writeTypeSuffixForObject(value, gen);
    }
    

    将为您的Human 实例打印{"pet":{"type":"dog":{"age":"7"}}}

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-08-02
      • 2019-05-20
      • 1970-01-01
      • 2013-10-10
      • 2017-06-12
      • 2017-11-23
      • 1970-01-01
      • 2019-08-10
      相关资源
      最近更新 更多