Jackson 在 JAX-RS 端点的具体 class 上需要 @JsonSubTypes-property

Jackson requires @JsonSubTypes-property on concrete class in JAX-RS endpoint

我有多个 JAX-RS 端点,它们原则上可以工作并且可以访问,需要 Java DTO 形式的不同参数。 这些 DTO 的结构如下:

@JsonTypeInfo(
        use = JsonTypeInfo.Id.NAME,
        include = JsonTypeInfo.As.PROPERTY,
        property = "jsonTypeInfo")
@JsonSubTypes({
        @JsonSubTypes.Type(value = com.company.package.ChildDto.class, name = "ChildDto"),
})
public class ParentDto...

Child DTO:

public class ChildDto extends ParentDto...

另一个DTO直接使用child DTO作为属性

public class OtherDto {
    private ChildDto childDtoRef;
    // getters and setters

端点方法如下所示

@POST
@Path("/my-path")
public void methodName(OtherDto otherDto) {

请注意,两个 DTO 都没有标记为抽象(如果 IMO 没有区别),并且通过使用 OtherDto,端点直接使用 ChildDto,而不是 ParentDto class。如果 "jsonTypeInfo": "ChildDto" 是请求正文的一部分,则端点有效。但是,在这种情况下,应该没有必要,因为该方法无论如何只接受 child class。

如果我在请求正文的 JSON 中省略 "jsonTypeInfo" 属性,我会得到以下异常:

com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Missing type id when trying to resolve subtype of [simple
type, class com...ChildDto]: missing type id property 'jsonTypeInfo' (for
POJO property 'childDtoRef')
at [Source: (io.undertow.servlet.spec.ServletInputStreamImpl); line: 8, column: 5] (through reference chain:
...

我是不是做错了什么?或者我的期望是 jsonTypeInfo 属性 是不必要的,错了吗?无论如何,Jackson 永远不需要解析 ParentDto 实例。

我想不出一种方法来全局配置我想要的行为,而是找到了一种解决方法。在杰克逊回购的 this site 上,它指出

All instances of annotated type and its subtypes use these settings (unless overridden by another annotation)

意味着 ChildDto 继承了相同的 JsonTypeInfoJsonSubtypes 注释,传递性地也需要 ID 属性 jsonTypeInfo 存在。

因此,解决方法是用相同的内容覆盖 JsonTypeInfo 注释,但添加了 defaultImpl,这是一个

Optional property that can be used to specify default implementation class to use for deserialization if type identifier is either not present [...]

具体来说,将以下注释添加到您的 ChildDto class:

@JsonTypeInfo(
        use = JsonTypeInfo.Id.NAME,
        include = JsonTypeInfo.As.PROPERTY,
        property = "jsonTypeInfo",
        defaultImpl = ChildDto.class)