Using fastjson turned over again, and there are more attributes inexplicably. .

A colleague said that after using fastjson for JSON serialization and storing in the database, he found that the JSON string "inexplicably" had some more attributes! After looking at the code for help, I saw the properties of the basic type of boolean type starting with is, and then I saw fastjson, and I wanted to laugh.

recurrent

defineMyClass

public class MyClass {

    // boolean 类型的属性
    private boolean isActive;
    private boolean valid;

    // int 类型的属性
    private int id;

    // 默认构造器
    public MyClass() {
    }

    // 带有所有属性的构造器
    public MyClass(boolean isActive, boolean valid, int id) {
        this.isActive = isActive;
        this.valid = valid;
        this.id = id;
    }

    // isActive 的 getter 和 setter 方法
    public boolean isActive() {
        return isActive;
    }

    public void setActive(boolean isActive) {
        this.isActive = isActive;
    }

    // valid 的 getter 和 setter 方法
    public boolean getValid() {
        return valid;
    }

    public void setValid(boolean valid) {
        this.valid = valid;
    }

    // id 的 getter 和 setter 方法
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

Write the test code:

import com.alibaba.fastjson.JSON;

public class MyClassMain {
    public static void main(String[] args) {
        // 创建 MyClass 对象
        MyClass myClass = new MyClass(true, false, 123);

        // 使用 fastjson 序列化对象
        String jsonString = JSON.toJSONString(myClass);

        // 打印 JSON 字符串
        System.out.println(jsonString);
    }
}

result:

{“active”:true,“id”:123,“valid”:false}

We found that there is one more active attribute and one less isActive attribute!

Recommend an open source and free Spring Boot practical project:

https://github.com/javastacks/spring-boot-best-practice

analyze

Through debugging, it can be found that the problem occurs in the following function:

com.alibaba.fastjson.serializer.SerializeConfig#createJavaBeanSerializer(java.lang.Class<?>)

public final ObjectSerializer createJavaBeanSerializer(Class<?> clazz) {
    String className = clazz.getName();
    long hashCode64 = TypeUtils.fnv1a_64(className);
    if (Arrays.binarySearch(denyClasses, hashCode64) >= 0) {
        throw new JSONException("not support class : " + className);
    }

    // 关键
    SerializeBeanInfo beanInfo = TypeUtils.buildBeanInfo(clazz, null, propertyNamingStrategy, fieldBased);
    if (beanInfo.fields.length == 0 && Iterable.class.isAssignableFrom(clazz)) {
        return MiscCodec.instance;
    }

    return createJavaBeanSerializer(beanInfo);
}

And the key to buildBeanInfo iscom.alibaba.fastjson.util.TypeUtils#computeGetters

public static List<FieldInfo> computeGetters(Class<?> clazz, //
                                             JSONType jsonType, //
                                             Map<String,String> aliasMap, //
                                             Map<String,Field> fieldCacheMap, //
                                             boolean sorted, //
                                             PropertyNamingStrategy propertyNamingStrategy //
){
    // 省略部分代码

        if(methodName.startsWith("is")){
            if(methodName.length() < 3){
                continue;
            }
            if(returnType != Boolean.TYPE
                    && returnType != Boolean.class){
                continue;
            }
            char c2 = methodName.charAt(2);
            String propertyName;
            Field field = null;
            if(Character.isUpperCase(c2)){
                if(compatibleWithJavaBean){
                    propertyName = decapitalize(methodName.substring(2));
                } else{
                    propertyName = Character.toLowerCase(methodName.charAt(2)) + methodName.substring(3);
                }
                // 这里 isActive 的属性名被计算出 active
                propertyName = getPropertyNameByCompatibleFieldName(fieldCacheMap, methodName, propertyName, 2);
            }

            // 省略其他

             JSONField fieldAnnotation = null;
            if(field != null){
                fieldAnnotation = TypeUtils.getAnnotation(field, JSONField.class);
                if(fieldAnnotation != null){
                    if(!fieldAnnotation.serialize()){
                        continue;
                    }
                    ordinal = fieldAnnotation.ordinal();
                    serialzeFeatures = SerializerFeature.of(fieldAnnotation.serialzeFeatures());
                    parserFeatures = Feature.of(fieldAnnotation.parseFeatures());
                    if(fieldAnnotation.name().length() != 0){
                        //关键: 使用 JSONField 注解设置的 name 替代属性名
                        propertyName = fieldAnnotation.name();
                        if(aliasMap != null){
                            propertyName = aliasMap.get(propertyName);
                            if(propertyName == null){
                                continue;
                            }
                        }
                    }
                    if(fieldAnnotation.label().length() != 0){
                        label = fieldAnnotation.label();
                    }
                }
            }

            // 省略部分代码

            FieldInfo fieldInfo = new FieldInfo(propertyName, method, field, clazz, null, ordinal, serialzeFeatures, parserFeatures,
                    annotation, fieldAnnotation, label);
            fieldInfoMap.put(propertyName, fieldInfo);
        }
    }
    Field[] fields = clazz.getFields();
    computeFields(clazz, aliasMap, propertyNamingStrategy, fieldInfoMap, fields);
    return getFieldInfos(clazz, sorted, fieldInfoMap);
}

In fact, although fastjson has the ability to identify the real attribute name through reflection, it will deduce the attribute name according to the getter method in actual operation, resulting in a deviation from the actual attribute name when converted into a JSON string.

Solution

Follow the Alibaba Java Development Manual

Teacher Gu Jin's "Java Development Manual" specifically emphasizes that any Boolean variable should not be prefixed with is. When the basic type Boolean attribute is reversed, it will be mistaken that the attribute cannot be obtained without is, and an exception will be thrown. Pay attention to the official account: Java core technology, reply: manual, you can get the full HD version.

use an alias

Use the @JSONField annotation that comes with fastjson, but fastjson is too intrusive in this way.

public class MyClass {

    @JSONField( name="isActive")
    // boolean 类型的属性
    private boolean isActive;
    private boolean valid;

    // 省略其他

}

Summarize

I think that for Java programmers, "Alibaba Java Development Manual" should be read at least 3 times. Too many common low-level problems found in the work are problems that already exist in the "Alibaba Java Development Manual". Pay attention to the official account: Java core technology, reply: manual, you can get the full HD version.

However, although the "Alibaba Java Development Manual" is recommended many times, although it is very thin, many people still don't read it carefully several times, resulting in falling down many times in the same place. Even if you encounter a similar problem, it is easy to quickly figure out the reason.

When we encounter a problem, we must not stop at solving the problem, but should look for the most reasonable solution. For example, although adding @JSONFieldcan "solve the problem", it is too intrusive. If other people use this object to use other JSON serialization tools, problems will arise. This is not a good solution.

In the age of AI, if you encounter a problem and cannot solve it quickly, you can consider seeking help from AI. But when using AI, be sure to explain the problem clearly. Many students asked questions that even other colleagues could not understand, let alone AI.

Copyright statement: This article is an original article by CSDN blogger "Mingming Ruyue Senior", and follows the CC 4.0 BY-SA copyright agreement. For reprinting, please attach the original source link and this statement. Original link: https://blog.csdn.net/w605283073/article/details/131270338

Recent hot article recommendation:

1. 1,000+ Java interview questions and answers (2022 latest version)

2. Brilliant! Java coroutines are coming. . .

3. Spring Boot 2.x tutorial, too comprehensive!

4. Don't fill the screen with explosions and explosions, try the decorator mode, this is the elegant way! !

5. The latest release of "Java Development Manual (Songshan Edition)", download quickly!

Feel good, don't forget to like + forward!

Guess you like

Origin blog.csdn.net/youanyyou/article/details/131899519