toJsonString竟多了个字段?

144 阅读3分钟

1. 现象

我有一个类,其中有一个getInfo方法

@EqualsAndHashCode(callSuper = true)
@Data
public class Student extends AbstractUser{
    private String school;

    private String clazz;

    public String getInfo() {
        return toString();
    }
}

1.2

然后我将这个类的对象进行序列号后输出:

@Test
public void toJsonStringTest() {
    Student student = new Student();
    student.setSchool("");
    student.setClazz("");
    student.setName("");
    student.setAge(0);
    System.out.println(JSON.toJSONString(student));
}

1.3

发现最终输出的结果与预期不符:有一个info 的属性,fastjson在序列号的时候,将getInfo视作类的一个属性的get方法了

{"age":0,"clazz":"","info":"Student(school=, clazz=)","name":"","school":""}

2. 分析原因

2.1 JSON.java

首先,我们进入到toJSONString 的方法中,

public static String toJSONString(Object object, // 
                                    SerializeConfig config, // 
                                    SerializeFilter[] filters, // 
                                    String dateFormat, //
                                    int defaultFeatures, // 
                                    SerializerFeature... features) {
    SerializeWriter out = new SerializeWriter(null, defaultFeatures, features);

    try {
        JSONSerializer serializer = new JSONSerializer(out, config);
        
        if (dateFormat != null && dateFormat.length() != 0) {
            serializer.setDateFormat(dateFormat);
            serializer.config(SerializerFeature.WriteDateUseDateFormat, true);
        }

        if (filters != null) {
            for (SerializeFilter filter : filters) {
                serializer.addFilter(filter);
            }
        }
        //可以发现最核心的代码在这里,这里是实际上做序列化的地方
        serializer.write(object);

        return out.toString();
    } finally {
        out.close();
    }
}

2.2 JSONSerializer

在JSONSerializer中,会新建一个writer(ASM)进行序列号

public final void write(Object object) {
    if (object == null) {
        out.writeNull();
        return;
    }

    Class<?> clazz = object.getClass();
    //创建一个ASM的序列化writer
    ObjectSerializer writer = getObjectWriter(clazz);

    try {
        writer.write(this, object, null, null, 0);
    } catch (IOException e) {
        throw new JSONException(e.getMessage(), e);
    }
}

2.3 SerializeConfig

private ObjectSerializer getObjectWriter(Class<?> clazz, boolean create) {
    ObjectSerializer writer = serializers.get(clazz);
    //加载AutowiredObjectSerializer,自定义序列号器
    if (writer == null) {
    }
    //使用JSON 的类加载器再加载一下(如果不一样)
    if (writer == null) {
    }
    
    if (writer == null) {
        String className = clazz.getName();
        Class<?> superClass;

        //一些已经实现好的类,例如Map、枚举、一些异常类 这些特殊类;
        else {
            //java bean需要创建一个ASM 的writer
            if (create) {
                writer = createJavaBeanSerializer(clazz);
                put(clazz, writer);
            }
        }

        if (writer == null) {
            writer = serializers.get(clazz);
        }
    }
    return writer;
}

public final ObjectSerializer createJavaBeanSerializer(Class<?> clazz) {
    //首先获取到bean的信息,属性等字段;info数据也是在这里获取到的
    SerializeBeanInfo beanInfo = TypeUtils.buildBeanInfo(clazz, null, propertyNamingStrategy, fieldBased);
    if (beanInfo.fields.length == 0 && Iterable.class.isAssignableFrom(clazz)) {
        return MiscCodec.instance;
    }
    // 创建javaBean序列化器
    return createJavaBeanSerializer(beanInfo);
}

2.4 TypeUtils

通过反射获取到类的具体信息,并组装成BeanInfo

public static SerializeBeanInfo buildBeanInfo(Class<?> beanType //
            , Map<String,String> aliasMap //
            , PropertyNamingStrategy propertyNamingStrategy //
            , boolean fieldBased //
){
    JSONType jsonType = TypeUtils.getAnnotation(beanType,JSONType.class);
    String[] orders = null;
    final int features;
    String typeName = null, typeKey = null;
    if(jsonType != null){
        orders = jsonType.orders();

        typeName = jsonType.typeName();
        if(typeName.length() == 0){
            typeName = null;
        }

        PropertyNamingStrategy jsonTypeNaming = jsonType.naming();
        if (jsonTypeNaming != null && jsonTypeNaming != PropertyNamingStrategy.CamelCase) {
            propertyNamingStrategy = jsonTypeNaming;
        }

        features = SerializerFeature.of(jsonType.serialzeFeatures());
        for(Class<?> supperClass = beanType.getSuperclass()
            ; supperClass != null && supperClass != Object.class
                ; supperClass = supperClass.getSuperclass()){
            JSONType superJsonType = TypeUtils.getAnnotation(supperClass,JSONType.class);
            if(superJsonType == null){
                break;
            }
            typeKey = superJsonType.typeKey();
            if(typeKey.length() != 0){
                break;
            }
        }

        for(Class<?> interfaceClass : beanType.getInterfaces()){
            JSONType superJsonType = TypeUtils.getAnnotation(interfaceClass,JSONType.class);
            if(superJsonType != null){
                typeKey = superJsonType.typeKey();
                if(typeKey.length() != 0){
                    break;
                }
            }
        }

        if(typeKey != null && typeKey.length() == 0){
            typeKey = null;
        }
    } else{
        features = 0;
    }
    // fieldName,field ,先生成fieldName的快照,减少之后的findField的轮询
    Map<String,Field> fieldCacheMap = new HashMap<String,Field>();
    // 在这里获取到定义好的属性
    ParserConfig.parserAllFieldToCache(beanType, fieldCacheMap);
    //这里将一些方法也作为属性封装
    List<FieldInfo> fieldInfoList = fieldBased
            ? computeGettersWithFieldBase(beanType, aliasMap, false, propertyNamingStrategy) //
            : computeGetters(beanType, jsonType, aliasMap, fieldCacheMap, false, propertyNamingStrategy);
    FieldInfo[] fields = new FieldInfo[fieldInfoList.size()];
    fieldInfoList.toArray(fields);
    FieldInfo[] sortedFields;
    List<FieldInfo> sortedFieldList;
    if(orders != null && orders.length != 0){
        sortedFieldList = fieldBased
                ? computeGettersWithFieldBase(beanType, aliasMap, true, propertyNamingStrategy) //
                : computeGetters(beanType, jsonType, aliasMap, fieldCacheMap, true, propertyNamingStrategy);
    } else{
        sortedFieldList = new ArrayList<FieldInfo>(fieldInfoList);
        Collections.sort(sortedFieldList);
    }
    sortedFields = new FieldInfo[sortedFieldList.size()];
    sortedFieldList.toArray(sortedFields);
    if(Arrays.equals(sortedFields, fields)){
        sortedFields = fields;
    }
    return new SerializeBeanInfo(beanType, jsonType, typeName, typeKey, features, fields, sortedFields);
}

public static List<FieldInfo> computeGetters(Class<?> clazz, //
                                                JSONType jsonType, //
                                                Map<String,String> aliasMap, //
                                                Map<String,Field> fieldCacheMap, //
                                                boolean sorted, //
                                                PropertyNamingStrategy propertyNamingStrategy //
){
    Map<String,FieldInfo> fieldInfoMap = new LinkedHashMap<String,FieldInfo>();
    boolean kotlin = TypeUtils.isKotlin(clazz);
    // for kotlin
    Constructor[] constructors = null;
    Annotation[][] paramAnnotationArrays = null;
    String[] paramNames = null;
    short[] paramNameMapping = null;
    Method[] methods = clazz.getMethods();
    // 遍历方法
    for(Method method : methods){
        String methodName = method.getName();
        int ordinal = 0, serialzeFeatures = 0, parserFeatures = 0;
        String label = null;
        //将void 或者 其他不满足条件的方法给过滤了
        //将get方法get后面的作为数值
        if(methodName.startsWith("get")){
            fieldInfoMap.put(propertyName, fieldInfo);
        }
    }
    Field[] fields = clazz.getFields();
    computeFields(clazz, aliasMap, propertyNamingStrategy, fieldInfoMap, fields);
    return getFieldInfos(clazz, sorted, fieldInfoMap);
}

3. 结果

最终在fastJson生成的ASM序列号器中就会有一个由getInfo方法得到的info属性,最终序列化的时候会将info数据也给打印出来