作者:微信小助手
发布时间:2022-01-25T13:26:03
1. 先尝试找空参构造方法和 get\set 方法,如果有,直接利用这两个反序列化。 2. 如果没有,尝试找有参构造方法,但需要通过 @ConstructorProperties 来寻找。 1. 老版本的 fastjson 是不尝试寻找合适的有参构造,除非写了 JSONCreator 注解。 2. jackson 也是不尝试自己寻找,但可以借助 lombok 或用户自己写的 ConstructorProperties 注解。 3. 新版本的 fastjson 比较卷,还会自己尝试通过 asm 的方式强行帮你找到。
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.18</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.3</version>
</dependency>
</dependencies>package com.flash;
import lombok.AllArgsConstructor;
@ToString
@AllArgsConstructor
public class Student {
private int age;
}package com.flash;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
public class TestLombokJackson {
public static void main(String[] args) throws IOException {
String json = "{\"age\":1}";
Student s = new ObjectMapper().readValue(json, Student.class);
System.out.println(s);
}
}Student(age=1)
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.3</version>
</dependency>
</dependencies>Exception in thread "main" com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `com.flash.Student` (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (String)"{"age":1}"; line: 1, column: 2]
at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:63)
at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1342)
at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1031)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1275)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:325)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:159)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4001)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2992)
at com.flash.TestLombokJackson.main(TestLombokJackson.java:10)
Process finished with exit code 1
package com.flash;
import java.beans.ConstructorProperties;
public class Student {
private int age;
public String toString() {
return "Student(age=" + this.age + ")";
}
@ConstructorProperties({"age"})
public Student(int age) {
this.age = age;
}
}package com.flash;
public class Student {
private int age;
public String toString() {
return "Student(age=" + this.age + ")";
}
public Student(int age) {
this.age = age;
}
}
@Override
public Boolean hasCreatorAnnotation(Annotated a) {
ConstructorProperties props =
a.getAnnotation(ConstructorProperties.class);
if (props != null) {
return Boolean.TRUE;
}
return null;
}protected Object deserializeFromObjectUsingNonDefault(JsonParser p,
DeserializationContext ctxt) throws IOException {
...
if (_propertyBasedCreator != null) {
return _deserializeUsingPropertyBased(p, ctxt);
}
...
return ctxt.handleMissingInstantiator(raw, getValueInstantiator(), p,
"cannot deserialize from Object value (no delegate- or property-based Creator)");
}
package com.flash;
import lombok.AllArgsConstructor;
@ToString
@AllArgsConstructor
public class Student {
private int age;
}package com.flash;
import com.alibaba.fastjson.JSONObject;
import java.io.IOException;
public class TestLombokJackson {
public static void main(String[] args) throws IOException {
String json = "{\"age\":1}";
Student s = JSONObject.parseObject(json, Student.class);
System.out.println(s);
}
}Exception in thread "main" com.alibaba.fastjson.JSONException: default constructor not found. class com.flash.Student
at com.alibaba.fastjson.util.JavaBeanInfo.build(JavaBeanInfo.java:224)
at com.alibaba.fastjson.parser.ParserConfig.createJavaBeanDeserializer(ParserConfig.java:574)
at com.alibaba.fastjson.parser.ParserConfig.getDeserializer(ParserConfig.java:491)
at com.alibaba.fastjson.parser.ParserConfig.getDeserializer(ParserConfig.java:348)
at com.alibaba.fastjson.parser.DefaultJSONParser.parseObject(DefaultJSONParser.java:639)
at com.alibaba.fastjson.JSON.parseObject(JSON.java:350)
at com.alibaba.fastjson.JSON.parseObject(JSON.java:254)
at com.alibaba.fastjson.JSON.parseObject(JSON.java:467)
at com.flash.TestLombokJackson.main(TestLombokJackson.java:12)
Student(age=1)
public static JavaBeanInfo build(...) {
...
// 直接获取默认空参构造
Constructor[] constructors = clazz.getDeclaredConstructors();
defaultConstructor = getDefaultConstructor(clazz, constructors);
...
// 默认空参不存在的话
if (defaultConstructor == null){
...
for (Constructor constructor : constructors) {
...
// 通过 asm 方式寻找参数名
paramNames = ASMUtils.lookupParameterNames(constructor);
...
}
...
// 找到了就可以正常返回了
if (paramNames != null && ...) {
...
return new JavaBeanInfo(...);
}
// 原来是直接到下面这句,不经过上面 asm 寻找名的过程
throw new JSONException("default constructor not found. " + clazz);
}
...
}