錯誤場景
用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反序列化
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表示了該實體類是否含有默認無參構造函數(通過反射機制獲得)。
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(?)。最后判斷一下是否是內部靜態類,進入異常處理部分。