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

Jackson中无注释的多态反序列化

朱俊雅
2023-03-14

我有一个CloudEvent

@Data
@NoArgsConstructor
@AllArgsConstructor
public class CloudEvent<T> {

    @NonNull
    private String eventType;

    @JsonTypeInfo(
            use = JsonTypeInfo.Id.NAME,
            include = JsonTypeInfo.As.EXTERNAL_PROPERTY,
            property = "eventType",
            defaultImpl = Void.class)
    @JsonSubTypes({
            @JsonSubTypes.Type(value = MyEvent1.class, name = "event-1"),
            @JsonSubTypes.Type(value = MyEvent2.class, name = "event-2")
    })
    private T data;
}

然后反序列化为:

String cloudEventJson1 = "{\"eventType\":\"event-1\",\"data\":{\"id\":\"123\",\"details\":\"detail1\"}}";

CloudEvent deserializedEvent1 = objectMapper.readValue(cloudEventJson1, CloudEvent.class);   //without subtypes

所有这些都很好。但由于一些限制,我无法在CloudEvent类(由外部依赖提供)上使用注释。

因此,我对ObjectMapper进行了如下配置:

    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.registerSubtypes(new NamedType(MyEvent1.class, "event-1"));
    objectMapper.registerSubtypes(new NamedType(MyEvent2.class, "event-2"));

    TypeResolverBuilder  typeResolverBuilder = new ObjectMapper.DefaultTypeResolverBuilder(ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE)
      .init(JsonTypeInfo.Id.NAME, null)   //CLASS works
      .inclusion(JsonTypeInfo.As.EXTERNAL_PROPERTY)
      .typeProperty("eventType")
      .typeIdVisibility(true)
//    .defaultImpl(Void.class);
    objectMapper.setDefaultTyping(typeResolverBuilder);

但使用上述相同的方法反序列化不起作用。它正在读取事件类型,但无法与注册的子类型匹配。我不能在反序列化中使用泛型或类型引用,因为我需要使用spring集成来读取只接受main类的事件;反序列化后手动执行的模式匹配。

例外:

com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Could not resolve type id 'event-1' as a subtype of [simple type, class java.lang.Object]: known type ids = [] (for POJO property 'data')
 at [Source: (String)"{"eventType":"event-1","data":{"id":"123","details":"detail1"}}"; line: 1, column: 271]

这也是为所有输入类配置ObjectMapper。是否可以将此类型ResolverBuilder和子类型连接到CloudEvent。类(就像注释方式一样)。


共有1个答案

林泰平
2023-03-14

即使不能修改类,也可以依赖注释。Jackson支持一个名为mix-ins的特性:您可以将其视为一种面向方面的方式,在运行时添加更多注释,以增强静态定义的注释。

首先定义一个接口,如下所示:

public interface CloudEventMixIn<T> {

     @JsonTypeInfo(
            use = JsonTypeInfo.Id.NAME,
            include = JsonTypeInfo.As.EXTERNAL_PROPERTY,
            property = "eventType",
            defaultImpl = Void.class)
    @JsonSubTypes({
            @JsonSubTypes.Type(value = MyEvent1.class, name = "event-1"),
            @JsonSubTypes.Type(value = MyEvent2.class, name = "event-2")
    })
    public T getData();
}

然后配置ObjectMapper,将定义的接口用作实际类/接口的混合:

ObjectMapper mapper = new ObjectMapper();
mapper.addMixIn(CloudEvent.class, CloudEventMixIn.class);

从addMixIn(类

方法,用于添加混合注释以用于扩充指定的类或接口。来自mixinSource的所有注释都会覆盖target(或其超类型)所具有的注释。

 类似资料:
  • 我想使用jackson注释反序列化2级多态子类型。基本上,我想使用json注释和jacksons将以下json转换为xml,如下所示 我想要的最终Xml是 我有以下几门课——主课 它具有抽象子类 MySubItem有具体的子类,比如MySubItemA、MySubItemB和MySubItemC 最后,我们创建一个客户端类,它包含抽象类的对象列表 我尝试为我的项目创建 Mixin 类作为 和for

  • 我对Jackson和类型层次结构有以下问题。我正在序列化一个类SubA,该类将扩展为一个字符串,然后尝试将其反序列化回来。当然,在编译时,系统不知道它是基还是SubA,因此我希望它是基,如果它是SubA,则会在编译后执行一些其他操作。 我的基本类看起来像: ...和一个派生自的类: ... 我试图执行以下代码: String是: 但我一次又一次地犯同样的错误。映射器现在知道如何处理另一个类参数-它

  • 我想为我们的REST API实现一个自定义的反序列化器,它不仅被Java应用程序使用。因此,我不想让Jackson将类型信息放入序列化的JSON中。 我目前正在努力反序列化<code>CollectionExpand</code>,因为它包含特定<code>ResourceModel</code>的<code>数据</code>列表。 < code>ResourceModel是一个接口,每个< c

  • 我有以下几个类,我想使用Jackson反序列化JSON字符串。 PushNotificationMessage.java 设备信息。Java语言 IOSDeviceInfo。Java语言 WebDeviceInfo.java 我有以下要反序列化的JSON内容: 我只需使用ObjectMapper来尝试执行反序列化。 当我这样做时,我得到: com.fasterxml.jackson.databin

  • 我看过jackson反序列化@JsonTypeInfo的一个例子,那就是: 我试过了,效果很好。现在的问题是,在示例类中,Cat和Dog是从Animal中引用的,我想避免这种情况。有没有一种方法可以将类型绑定从类动物中移除,并且仍然进行反序列化工作?谢谢

  • 我给一个有json主体的aws lambda打电话。因此,json的字段与POJO中的字段具有不同的名称。所以我所做的就是在字段中添加@JsonProperty,告诉jackson json中的名称。但出于某种原因,它似乎无法识别它们,并且所有字段都为空。如果我传递一个与POJO具有相同字段名的json,它就会工作。这是我的课: 如果我通过 所有的字段都是空的,并且有明显的ID、userId、ev