升级到 Spring Boot 2 后,ObjectMapper 无法在没有默认构造函数的情况下反序列化

新手上路,请多包涵

我有以下 DTO:

 @Value
public class PracticeResults {
    @NotNull
    Map<Long, Boolean> wordAnswers;
}

@Value
public class ProfileMetaDto {

    @NotEmpty
    String name;
    @Email
    String email;
    @Size(min = 5)
    String password;
}

@Value 是生成构造函数的 Lombok 注释。这意味着此类没有无参数构造函数。

我使用了 Spring Boot 1.4.3.RELEASE 和 ObjectMapper bean 能够从 JSON 反序列化此类对象。

升级到 Spring Boot 2.0.0.M7 后,我收到以下异常:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of PracticeResults (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

Spring Boot 1.4.3 中使用的 Jackson 版本是 2.8.10 而 Spring Boot 2.0.0.M7 是 2.9.2

我试过用谷歌搜索这个问题,但只找到了 @JsonCreator@JsonProperty 的解决方案。

那么,为什么它适用于 Spring Boot 1.4.3 而无法适用于 Spring Boot 2?是否可以将 bean 配置为与旧版本的行为方式相同?

原文由 solomkinmv 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.2k
2 个回答

由于 Lombok 版本 1.16.20 中的重大更改,您需要在 lombok.config 文件中设置以下属性(如果您没有此文件,可以在项目根目录中创建它):

 lombok.anyConstructor.addConstructorProperties=true

Lombok 更新日志中对此进行了描述: https ://projectlombok.org/changelog。

之后 @Value 应该再次被 Jackson 接受。

您可能有兴趣在此处关注相关的 GitHub 问题,尽管它是关于 @Datahttps ://github.com/rzwitserloot/lombok/issues/1563

原文由 Tobias 发布,翻译遵循 CC BY-SA 4.0 许可协议

解决这个问题的另一种方法。使用 Jackson parameter names module ,它默认包含在 spring boot 2 中。在此之后,杰克逊可以反序列化对象。但只有当你在对象中有超过 1 个属性时它才有效。如果是单个属性,我会收到以下错误消息:

 com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `SomeClassName` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

由于以下原因:

可用于将构造函数和工厂方法定义为用于实例化关联类的新实例的标记注释。

注意:在注释创建者方法(构造函数、工厂方法)时,方法必须是:

  • 没有 JsonProperty 参数注释的单参数构造函数/工厂方法:如果是这样,这就是所谓的“委托创建者”,在这种情况下,Jackson 首先将 JSON 绑定到参数的类型中,然后调用创建者.这通常与 JsonValue 一起使用(用于序列化)。
  • 构造函数/工厂方法,其中每个 参数 都用 JsonPropertyJacksonInject 注释,以指示要绑定到的属性的名称

另请注意,所有 JsonProperty 注释必须指定实际名称(“默认”不是空字符串),除非您使用可以检测参数名称的扩展模块之一;这是因为 8 之前的默认 JDK 版本无法从字节码存储和/或检索参数名称。但是对于 JDK 8(或使用辅助库,如 Paranamer,或其他 JVM 语言,如 Scala 或 Kotlin),指定名称是可选的。

为了使用 Lombok 处理这种情况,我使用了以下解决方法:

 @Value
@AllArgsConstructor(onConstructor = @__(@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)))
class SomeClassName {...}

原文由 solomkinmv 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题