Background
线上使用lombok-1.16.20版本的依赖生成相关model对象的getter/setter/constructor/builder相关方法。但是在升级了1.16.20版本后线上Jackson反序列化报错:
“no suitable constructor found, can not deserialize from Object value (missing default constructor or creator, or perhaps need to add/enable type information?)”)
Problem
@Builder的使用问题
如果使用@Builder注解,在1.16.20版本下会生成包访问权限的全参构造函数,没有无参数构造函数(用1.16.18也不会生成无参数构造函数)
1
2
3
4
5
6
7
ResourceConfigRule(int type, String url, String scale, String webpUrl, String webpScaleUrl, boolean needVerify)
{
this.type = type;this.url = url;this.scale = scale;this.webpUrl = webpUrl;this.webpScaleUrl = webpScaleUrl;this.needVerify = needVerify;
}
这种生成的字节码会在jackson反序列化的时候报错找不到合适的构造函数。
临时策略
添加@AllArgsConstructor和@NoArgsConstructor,在生成的字节码中看到此时会将对应的构造函数声明为public和public 访问权限的生成无参数构造函数,即@Builder的构造函数策略被覆盖,此时就不会报错可以正常反序列化json为对象
1
2
3
4
5
6
7
8
9
public ResourceConfigRule(int type, String url, String scale, String webpUrl, String webpScaleUrl, boolean needVerify)
{
this.type = type;this.url = url;this.scale = scale;this.webpUrl = webpUrl;this.webpScaleUrl = webpScaleUrl;this.needVerify = needVerify;
}
public ResourceConfigRule() {}
原因
但是这并不是1.16.20报错的原因,即不添加@AllArgsConstructor和@NoArgsConstructor在1.16.18版本中也不会报错,而只使用了@Data、@Builder。
反编译一下代码发现两个版本生成的字节码是不同的,18版本的全参构造函数有一个注解@ConstructorProperties
1
2
3
4
5
6
7
8
9
@ConstructorProperties({"type", "url", "scale", "webpUrl", "webpScaleUrl", "needVerify"})
ResourceConfigRule(int type, String url, String scale, String webpUrl, String webpScaleUrl, boolean needVerify)
{
this.type = type;this.url = url;this.scale = scale;this.webpUrl = webpUrl;this.webpScaleUrl = webpScaleUrl;this.needVerify = needVerify;
}
这个注解在1.16.18的changelog中有提到:
- CHANGE:
@ConstructorProperties
will now also be generated for private and package private constructors. This is useful for Jackson Issue #1180
也就说这个注解可以解决Jackson反序列化的问题的。
而1.16.20版本的changelog里有这么一条BREAKING CHANGE:
- BREAKING CHANGE: lombok config key
lombok.anyConstructor.suppressConstructorProperties
is now deprecated and defaults totrue
, that is, by default lombok no longer automatically generates@ConstructorProperties
annotations. New config keylombok.anyConstructor.addConstructorProperties
now exists; set it totrue
if you want the old behavior. Oracle more or less broke this annotation with the release of JDK9, necessitating this breaking change.
很明显最新的1.16.20版本已经将该注解suppress掉不再生成,但是保留了一个配置。这也是报错的根本原因,Jackson反序列化一个bean 的时候是采用了这种策略的,具体参考BeanDeserializerBase类的resolve()方法和
deserializeFromObjectUsingNonDefault()方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
protected Object deserializeFromObjectUsingNonDefault(JsonParser p,
DeserializationContext ctxt) throws IOException
{
final JsonDeserializer<Object> delegateDeser = _delegateDeserializer();
if (delegateDeser != null) {
return _valueInstantiator.createUsingDelegate(ctxt,
delegateDeser.deserialize(p, ctxt));
}
if (_propertyBasedCreator != null) {
return _deserializeUsingPropertyBased(p, ctxt);
}
// should only occur for abstract types...
if (_beanType.isAbstract()) {
return ctxt.handleMissingInstantiator(handledType(), p,
"abstract type (need to add/enable type information?)");
}
// 25-Jan-2017, tatu: We do not actually support use of Creators for non-static
// inner classes -- with one and only one exception; that of default constructor!
// -- so let's indicate it
Class<?> raw = _beanType.getRawClass();
if (ClassUtil.isNonStaticInnerClass(raw)) {
return ctxt.handleMissingInstantiator(raw, p,
"can only instantiate non-static inner class by using default, no-argument constructor");
}
return ctxt.handleMissingInstantiator(raw, p,
"no suitable constructor found, can not deserialize from Object value (missing default constructor or creator, or perhaps need to add/enable type information?)");
}
How to Fix
-
1.使用1.16.18版本,不需要修改老代码,最简单
-
2.使用最新版本,需要在project根路径下添加文件lombok.config,并且设置
lombok.anyConstructor.addConstructorProperties = true
-
3.如果使用了@Builder则添加@AllArgsConstructor和@NoArgsConstructor
-
4.如果没有使用@Builder,用@Data不会有这个问题,因为它会生成无参数public的构造函数
Reference
- https://docs.oracle.com/javase/7/docs/api/java/beans/ConstructorProperties.html
- https://github.com/rzwitserloot/lombok/issues/1180
- https://projectlombok.org/features/configuration
- https://projectlombok.org/changelog
本文首次发布于 LiuShuo’s Blog, 转载请保留原文链接.