使用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.新增默認的構造器

       2.方法形參列表最長的構造器中新增phone屬性(如果代碼已運行很久,建議新增構造器,方法形參列表最長,且包含phone字段)

 


免責聲明!

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



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