使用FastJson parseObject方法时,json字符串解析成对象后,部分属性丢失问题处理
·
出现此类问题的原因会有多种, 本文仅介绍发现的一种情况,不一定适用所有的场景
情景:
JavaBean 中没有默认的构造方法
例如:

public class Student{
public static void main(String[] args) {
String jsonStr = "{\"id\":1,\"name\":\"Ming\",\"age\":18,\"phone\":\"23333333333\",\"address\":\"杭州\"}";
Student student = JSON.parseObject(jsonStr, Student.class);
System.out.println(JSON.toJSONString(student));
}
private Long id;
private String name;
private Integer age;
private String address;
private String phone;
public Student(Long id, String name,String phone) {
this.id = id;
this.name = name;
this.phone = phone;
}
public Student(Long id, String name, Integer age, String address) {
this.id = id;
this.name = name;
this.age = age;
this.address = address;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}

运行结果: {"address":"杭州","age":18,"id":1,"name":"Ming"}
此时解析成对象后,会丢失phone属性.虽然有一个构造器是带有phone字段的.
原因:
FastJson 创建 JavaBean,调用了

#会调用以下构造方法
new JavaBeanDeserializer(this,clazz,type);
#构造方法详情
public JavaBeanDeserializer(ParserConfig config, Class<?> clazz, Type type){
this(config //
, JavaBeanInfo.build(clazz, type, config.propertyNamingStrategy, config.fieldBased, config.compatibleWithJavaBean, config.isJacksonCompatible())
);
}
#build方法确定使用哪个构造器的代码片段
for (Constructor constructor : constructors) {
Class<?>[] parameterTypes = constructor.getParameterTypes();
if (className.equals("org.springframework.security.web.authentication.WebAuthenticationDetails")) {
if (parameterTypes.length == 2 && parameterTypes[0] == String.class && parameterTypes[1] == String.class) {
creatorConstructor = constructor;
creatorConstructor.setAccessible(true);
paramNames = ASMUtils.lookupParameterNames(constructor);
break;
}
}
if (className.equals("org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken")) {
if (parameterTypes.length == 3
&& parameterTypes[0] == Object.class
&& parameterTypes[1] == Object.class
&& parameterTypes[2] == Collection.class) {
creatorConstructor = constructor;
creatorConstructor.setAccessible(true);
paramNames = new String[] {"principal", "credentials", "authorities"};
break;
}
}
if (className.equals("org.springframework.security.core.authority.SimpleGrantedAuthority")) {
if (parameterTypes.length == 1
&& parameterTypes[0] == String.class) {
creatorConstructor = constructor;
paramNames = new String[] {"authority"};
break;
}
}
//
boolean is_public = (constructor.getModifiers() & Modifier.PUBLIC) != 0;
if (!is_public) {
continue;
}
String[] lookupParameterNames = ASMUtils.lookupParameterNames(constructor);
if (lookupParameterNames == null || lookupParameterNames.length == 0) {
continue;
}
if (creatorConstructor != null
&& paramNames != null && lookupParameterNames.length <= paramNames.length) {
continue;
}
paramNames = lookupParameterNames;
creatorConstructor = constructor;
}
# 可以看到这句判断,会迭代当前JavaBean的所有构造器,并取到构造器方法列表最长的那个构造器,作为JSON解析的构造器.
if (creatorConstructor != null && paramNames != null && lookupParameterNames.length <= paramNames.length) {
continue; }

根据以上代码可以看出,为什么丢失了phone属性.方法形参列表最长的构造器是没有phone属性的
解决方法:
1.新增默认的构造器(如果用的lombok则,对象增加@AllArgsConstructor注解,亲测,可用)
2.方法形参列表最长的构造器中新增phone属性(如果代码已运行很久,建议新增构造器,方法形参列表最长,且包含phone字段)
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)