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
ObjectMapper can't deserialize without default constructor after upgrade to Spring Boot 2
提问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;
}
@Value
is 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 ObjectMapper
bean was able to deserialize such object from JSON.
我使用了 Spring Boot 1.4.3.RELEASE 并且ObjectMapper
bean 能够从 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.10
and for Spring Boot 2.0.0.M7 is 2.9.2
.
Spring Boot 1.4.3 中使用的 Hymanson 版本是2.8.10
Spring Boot 2.0.0.M7 中使用的2.9.2
.
I've tried to Google this problem but found only solutions with @JsonCreator
or @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.config
file (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 问题,尽管它是关于@Data
:https: //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
JsonProperty
annotation 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 withJsonValue
(used for serialization).- Constructor/factory method where every argumentis annotated with either
JsonProperty
orHymansonInject
, to indicate name of property to bind toAlso note that all
JsonProperty
annotations 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.
我遇到了这个问题以及对我有用的解决方案,即创建没有字段的默认构造函数,问题就消失了。