当前位置: 首页 > 知识库问答 >
问题:

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

耿玄裳
2023-03-14

我目前正在将一些代码从Jackson1.x迁移到Jackson2.5json映射器,遇到了一个1.x中没有的问题。

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

  • 接口IPET
  • 类Dog实现IPET
  • IPET使用@jsonTypeInfo和@jsonSubtypes
  • 进行注释
  • 类Human具有一个类型为IPet的属性,该属性使用@JSONSerialize(using=CustompetSerializer.class)注释

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

com.fasterxml.jackson.databind.JSONMappingExcepthtml" target="_blank">ion:未为类型com.pet.dog实现类型id处理(通过引用链:com.human[“pet”])

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

代码:

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\""));
}

共有1个答案

彭俊智
2023-03-14

您还需要在CustompetSerializer中重写SerializeWithType,因为IPET是多态的。这也是不调用serialize的原因。检查这个相关的SO问题,该问题详细解释了何时调用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”}}}

 类似资料:
  • I'va是一个OID接口,可以由许多具体类型实现: 现在我有一个具有两个字段的对象,一个使用抽象接口类型(OID)定义,另一个使用具体类型(MyOID)定义 我想使用jackson以不同的方式序列化/反序列化字段,无论它们是使用抽象接口类型还是具体类型定义的: 注意,被序列化,包括类型信息(多态序列化),而被序列化为文本 为此,我将OID接口注释为: 并为每个具体类型分配了类型id: 最后,对容器

  • 我在序列化Jackson中的泛型对象时遇到问题。我已经找到了一个解决方法,但我仍然不知道为什么我原来的解决方案不起作用。以下是我的设置: 以下是我当前用于序列化方法的代码: 以下是应该起作用但不起作用的: 对于第二种情况,我得到了以下例外: 这是什么原因?从ClassB中的类型规范可以清楚地看出,列表中只能使用ParamClass,不能使用BaseParamClass。我错过什么了吗?

  • easyopen序列化使用fastjson处理json,xstream处理xml。现在我们来自定义实现一个json处理: 新建一个类JsonFormatter,实现ResultSerializer接口 public class JsonFormatter implements ResultSerializer { @Override public String serialize(

  • 我想反序列化表单中的类: 其中文本是加密的,反序列化应该在重建TestFieldEncryptedMessage实例之前取消对值的加密。 我采用的方法非常类似于:https://github.com/codesqueak/jackson-json-crypto 也就是说,我正在构建一个扩展SimpleModule的模块: 如您所见,设置了两个修饰符:EncryptedSerializerModif

  • 问题内容: 我的代码结构如下。 和 基本上我正在扫描网站以获取统计信息,例如标题标签,重复标题等。 我正在使用JQuery并向Web服务进行AJAX调用并检索url统计信息,而该过程正在运行以显示到目前为止收集的用户url统计信息,因为扫描大型网站需要花费大量时间。因此,每隔5秒,我就会从服务器检索统计信息。现在的问题是我需要在扫描处理完成时(而不是更新期间)最后发送所有List变量数据。现在发生

  • 我有一个JSON作为字符串,我将其反序列化并实例化为scala的MyPOJO case类。我的数据是YYYY-MM-DD格式,但POJO createdBy中的实际属性是LocalDateTime。 如何在实例化Pojo时指定默认时间值2020-03-02 00:00:00, 序列化应返回yyyy-mm-dd格式。我的序列化和反序列化格式不同。 我尝试过自定义序列化和反序列化,如下所示,但由于缺少