错误场景
用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(?)。最后判断一下是否是内部静态类,进入异常处理部分。