基于来自 JSON 请求主体的另一个属性,反序列化来自 JSON 请求主体的抽象属性

Posted

技术标签:

【中文标题】基于来自 JSON 请求主体的另一个属性,反序列化来自 JSON 请求主体的抽象属性【英文标题】:Deserializing abstract property from JSON request body, based on another property from that body 【发布时间】:2019-11-07 15:20:20 【问题描述】:

当一个对象具有一个抽象属性时,如何从 JSON 中正确反序列化(使用 Jackson)?

这可能最好用一个例子来描述。

我的 REST 端点的请求正文包含一个属性,该属性是具有多个具体实现的抽象类型,应基于 discriminator 属性进行反序列化:

@Getter
@Builder
@AllArgsConstructor
public class SomeRequestBody 

    @NotNull
    @NotBlank
    @NumberFormat
    private final String discriminator;

    @NotNull
    private final SomeAbstractClass someAbstractClass;


有问题的抽象类

@Getter
@AllArgsConstructor
public abstract class SomeAbstractClass

    @NotNull
    @NotBlank
    protected final String commonProperty;


抽象类的示例实现

@Getter
public class ConcreteImplementationA extends SomeAbstractClass 

    @Builder
    @JsonCreator
    public ConcreteImplementationA(
        @NotNull @NotBlank @JsonProperty("commonProperty") String commonProperty,
        @NotNull @NotBlank @JsonProperty("specificProperty") Date specificProperty) 
            super(commonProperty);
            this.specificProperty = specificProperty;
    

    @NotNull
    @NotBlank
    private final String specificProperty;


我尝试了什么...

@Getter
@Builder
@AllArgsConstructor
public class SomeRequestBody 

    @NotNull
    @NotBlank
    @NumberFormat
    private final String discriminator;

    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "discriminator")
    @JsonSubTypes(
        @JsonSubTypes.Type(value = ConcreteImplementationA.class, name = "1"),
        Other implementations...)
    )
    @NotNull
    private final SomeAbstractClass someAbstractClass;


但是,我遇到了以下异常:

"Type definition error: [simple type, class abc.SomeRequestBody]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `abc.SomeRequestBody`, problem: Internal error: no creator index for property 'someAbstractClass' (of type com.fasterxml.jackson.databind.deser.impl.FieldProperty)\n at [Source: (PushbackInputStream); line: 8, column: 1]"

实现我需要的正确方法是什么?

【问题讨论】:

【参考方案1】:

事实证明,该抽象属性的反序列化不是问题,但不可变属性和 Lombok 的 @AllArgsConstructor 与 Jackson 不兼容。我创建了一个 @JsonCreator 带注释的构造函数,而不是使用注释,现在它可以正常工作了。

【讨论】:

不是构建自己的构造函数,添加它也应该有效@AllArgsConstructor(onConstructor = @__(@JsonCreator)),至少对我来说它有效。 如果您的大多数对象都是这样不可变的,并且您不想为每个类添加配置详细信息...您可以创建一个 lombik.config 属性为 lombok.anyConstructor.addConstructorProperties=true 的文件它。这将导致 lombok 将 Java 注释添加到构造函数参数,并命名它们,Jackson 可以使用。

以上是关于基于来自 JSON 请求主体的另一个属性,反序列化来自 JSON 请求主体的抽象属性的主要内容,如果未能解决你的问题,请参考以下文章

System.Text.Json 反序列化来自 API 调用的嵌套对象 - 数据包装在父 JSON 属性中

Json.net反序列化不反序列化所有属性

使用 JSON-B / Yasson 将 JSON 反序列化为多态 POJO

如何根据json中的属性编写jackson反序列化器

尝试反序列化 JSON 对象数组,其中对象具有数组作为属性。我可以将数组元素映射到类的特定属性吗?

如何在 Spring 将其反序列化为 POJO 之前访问原始请求有效负载? [复制]