Spring Boot在反序列化過程中:jackson.databind.exc.InvalidDefinitionException cannot deserialize from Object value


錯誤場景

用Spring boot寫了一個簡單的RESTful API,在測試POST請求的時候,request body是一個符合對應實體類要求的json串,post的時候報錯。

先貼一段error log:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.yucfeng.Entity.EData` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
 at [Source: (PushbackInputStream); line: 2, column: 2]
    at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67) ~[jackson-databind-2.9.5.jar:2.9.5]
    at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1451) ~[jackson-databind-2.9.5.jar:2.9.5]
    at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1027) ~[jackson-databind-2.9.5.jar:2.9.5]
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1290) ~[jackson-databind-2.9.5.jar:2.9.5]
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:326) ~[jackson-databind-2.9.5.jar:2.9.5]
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:159) ~[jackson-databind-2.9.5.jar:2.9.5]

先說結論

原因:

原因是我在該實體類中添加了一個為了方便實例化該類用的構造函數,導致JVM不會添加默認的無參構造函數,而jackson的反序列化需要無參構造函數,因此報錯。

Response實體類同理。

解決:

在實體類中補上一個無參構造器即可。

Jackson反序列化

過debug,讓我們來看這一部分的源碼:
Jackson中有個BeanDeserializerBase類,該抽象類的子類BeanDeserializer包含了將字節流反序列化的一系列方法:如deserializeFromObject(JsonParser p, DeserializationContext ctxt)、deserialize(JsonParser p, DeserializationContext ctxt)。
在deserializeFromObject方法中,有這么一條判斷語句:
if (this._nonStandardCreation)

  該屬性_nonStandardCreation在BeanDeserializerBase類中是這樣定義的:

this._nonStandardCreation = this._unwrappedPropertyHandler != null || this._valueInstantiator.canCreateUsingDelegate() || 
this._valueInstantiator.canCreateUsingArrayDelegate() || this._valueInstantiator.canCreateFromObjectWith() || !this._valueInstantiator.canCreateUsingDefault();

  我們把目光放到 this._valueInstantiator.canCreateUsingDefault()上:

public boolean canCreateUsingDefault() {
      return this._defaultCreator != null;
  }

  _defaultCreator表示了該實體類是否含有默認無參構造函數(通過反射機制獲得)。

上文提 到了,我們添加了新的構造函數,JVM並未給該實體類添加默認無參構造函數,因此_defaultCreator為null。回到最初的判斷語句,這里的this._nonStandardCreation便是true。
當沒有無參構造函數,BeanDeserializer會怎么處理呢?
它會嘗試查找該類是否擁有_unwrappedPropertyHandler或者_externalTypeIdHandler,當然並沒有。那么調用deserializeFromObjectUsingNonDefault方法進行deserialize。
protected Object deserializeFromObjectUsingNonDefault(JsonParser p, DeserializationContext ctxt) throws IOException {
      JsonDeserializer<Object> delegateDeser = this._delegateDeserializer();
      if (delegateDeser != null) {
          return this._valueInstantiator.createUsingDelegate(ctxt, delegateDeser.deserialize(p, ctxt));
      } else if (this._propertyBasedCreator != null) {
          return this._deserializeUsingPropertyBased(p, ctxt);
      } else {
          Class<?> raw = this._beanType.getRawClass();
          return ClassUtil.isNonStaticInnerClass(raw) ? ctxt.handleMissingInstantiator(raw, (ValueInstantiator)null, p, "can only instantiate non-static inner class by using default, no-argument constructor", new Object[0]) : ctxt.handleMissingInstantiator(raw, this.getValueInstantiator(), p, "cannot deserialize from Object value (no delegate- or property-based Creator)", new Object[0]);
      }
  }

  在該方法中它判斷了兩個屬性:_delegateDeserializer和_propertyBasedCreator,對於這兩個屬性我也不是很明白。通過查閱API文檔,前者表示委托反序列化Deserializer that is used if delegate-based creator is to be used for deserializing from JSON Object.,后者表示If the bean needs to be instantiated using constructor or factory method that takes one or more named properties as argument(s), this creator is used for instantiation(?)。最后判斷一下是否是內部靜態類,進入異常處理部分。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM