Java程序员IT干货

lombok反序列化报错原因定位

2018-10-11  本文已影响1635人  ElseF

公众号请关注ElseF,ElseF(Else Figure),是一个专注于「分享」国内外高质量的科技类文章和新闻的自媒体。维护者主要来自国内外大型互联网公司和创业公司,主要专注于与互联网相关的精彩内容。


微信公众号

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也不会生成无参数构造函数)

  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为对象

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

@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 to true,
    that is, by default lombok no longer automatically generates @ConstructorProperties annotations. New config key lombok.anyConstructor.addConstructorProperties now exists;
    set it to true 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()方法

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

lombok.anyConstructor.addConstructorProperties = true

Reference

本文首次发布于 Elsef's Blog, 作者 @stuartlau ,转载请保留原文链接.

上一篇 下一篇

猜你喜欢

热点阅读