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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/48330613/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 02:48:59  来源:igfitidea点击:

ObjectMapper can't deserialize without default constructor after upgrade to Spring Boot 2

javaspringspring-bootHymansonlombok

提问by solomkinmv

I have following DTOs:

我有以下 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;
}

@Valueis a Lombok annotation which generates a constructor. Which means that this class doesn't have a no-arg constructor.

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

I used Spring Boot 1.4.3.RELEASE and ObjectMapperbean was able to deserialize such object from JSON.

我使用了 Spring Boot 1.4.3.RELEASE 并且ObjectMapperbean 能够从 JSON 反序列化这样的对象。

After the upgrade to Spring Boot 2.0.0.M7 I receive following exception:

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

com.fasterxml.Hymanson.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)

com.fasterxml.Hymanson.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)

Hymanson version used in Spring Boot 1.4.3 is 2.8.10and for Spring Boot 2.0.0.M7 is 2.9.2.

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

I've tried to Google this problem but found only solutions with @JsonCreatoror @JsonProperty.

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

So, why does it work with Spring Boot 1.4.3 and fails with Spring Boot 2? Is it possible to configure bean to behave the same way as the older version?

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

采纳答案by Tobias

Due to breaking changes in Lombok version 1.16.20 you need to set the following property in your lombok.configfile (if you don't have this file you can create it in your project root):

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

lombok.anyConstructor.addConstructorProperties=true

This is described in the Lombok changelog: https://projectlombok.org/changelog.

这在 Lombok 变更日志中有描述:https: //projectlombok.org/changelog

After that the @Value should be accepted again by Hymanson.

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

You may be interested in following the related GitHub issue here, although it's about @Data: https://github.com/rzwitserloot/lombok/issues/1563

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

回答by fascynacja

I have upgraded lombok version to : 'org.projectlombok:lombok:1.18.0' and it worked for me.

我已将 lombok 版本升级为:'org.projectlombok:lombok:1.18.0' 并且它对我有用。

回答by solomkinmv

One more way to solve this problem. Use Hymanson parameter names module, which is included in spring boot 2 by default. After this Hymanson can deserialize objects. But it works only if you have more than 1 property in object. In case of single property I receive following error message:

解决此问题的另一种方法。使用 Hymanson参数名称 module,它默认包含在 spring boot 2 中。在此之后,Hyman逊可以反序列化对象。但它只有在对象中有 1 个以上的属性时才有效。如果是单个属性,我会收到以下错误消息:

com.fasterxml.Hymanson.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)

Because of the following:

因为以下几点:

Marker annotation that can be used to define constructors and factory methods as one to use for instantiating new instances of the associated class.

NOTE: when annotating creator methods (constructors, factory methods), method must either be:

  • Single-argument constructor/factory method without JsonPropertyannotation for the argument: if so, this is so-called "delegate creator", in which case Hymanson first binds JSON into type of the argument, and then calls creator. This is often used in conjunction with JsonValue(used for serialization).
  • Constructor/factory method where every argumentis annotated with either JsonPropertyor HymansonInject, to indicate name of property to bind to

Also note that all JsonPropertyannotations must specify actual name (NOT empty String for "default") unless you use one of extension modules that can detect parameter name; this because default JDK versions before 8 have not been able to store and/or retrieve parameter names from bytecode. But with JDK 8 (or using helper libraries such as Paranamer, or other JVM languages like Scala or Kotlin), specifying name is optional.

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

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

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

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

To handle this case with Lombok I've used following workaround:

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

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

回答by leeCoder

I had this issue and the solution that worked for me what creating a default constructor without fieldsand the problem disappeared.

我遇到了这个问题以及对我有用的解决方案,即创建没有字段默认构造函数,问题就消失了。