Java JSON Jackson-使用自定义序列化程序序列化多态类时出现异常

Java JSON Jackson-使用自定义序列化程序序列化多态类时出现异常,java,json,jackson,Java,Json,Jackson,我目前正在将一些代码从jackson1.x迁移到jackson2.5json映射器,这是一个在1.x中没有的问题 这是设置(请参见下面的代码): 接口IPet 类狗实现IPet IPet用@JsonTypeInfo和@JsonSubTypes进行注释 类Human有一个IPet类型的属性,该属性用@JsonSerialize(using=CustomPetSerializer.class)注释 问题: 如果我序列化了Dog的一个实例,它将按预期工作(类型信息也由Jackson添加到json字

我目前正在将一些代码从jackson1.x迁移到jackson2.5json映射器,这是一个在1.x中没有的问题

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

  • 接口IPet
  • 类狗实现IPet
  • IPet用@JsonTypeInfo和@JsonSubTypes进行注释
  • 类Human有一个IPet类型的属性,该属性用@JsonSerialize(using=CustomPetSerializer.class)注释
问题: 如果我序列化了Dog的一个实例,它将按预期工作(类型信息也由Jackson添加到json字符串中)。 但是,当我序列化Human类的实例时,会抛出一个异常,说明:

com.fasterxml.jackson.databind.JsonMappingException:类型id处理 未针对com.pet.Dog类型实施(通过参考链: com.Human[“宠物”])

未调用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 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);
        }
    }
}
狗的执行:

@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 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);
        }
    }
}
养狗的人:

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

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

@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 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);
        }
    }
}

您还需要在
CustomPetSerializer
中重写
serializeWithType
,因为
IPet
是多态的。这也是为什么不调用
serialize
的原因。检查在调用
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);
}

它将为您的
人类
实例打印
{“宠物”:{“类型”:“狗”:{“年龄”:“7”}}

自Jackson 2.9以来
writeTypePrefixForObject()
writeTypeSuffixForObject()
已被弃用(我不清楚原因)。在新方法下,现在似乎是:

@Override
public void serializeWithType(IPet value, JsonGenerator gen, 
        SerializerProvider provider, TypeSerializer typeSer) 
        throws IOException, JsonProcessingException {

  WritableTypeId typeId = typeSerializer.typeId(value, START_OBJECT);
  typeSer.writeTypePrefix(gen, typeId);
  serialize(value, gen, provider); // call your customized serialize method
  typeSer.writeTypeSuffix(gen, typeId);
}
现在有一个额外的行,所以不确定为什么它是向前迈出的一步,也许它更有效地重用
typeId
对象


来源:杰克逊的班级目前在硕士班。不是最好的源代码,但看不到任何升级文档解释该做什么。

我要求在上一行澄清反对意见。它不应该是
END\u OBJECT
?所以没有重用
typeId