fastJson的toJSONString解读

先从一个小问题上我们抛砖引玉一下

首先我们先做准备工作 我们声明一个bean

public class YunmiStoreStr {
    public String gome;

    public YunmiStoreStr(String gome) {
        this.gome = gome;
    }

}

 

这时我们尝试使用toJSONString打印出来我们的json信息

public static void main(String[] args) {

        YunmiStoreStr str = new YunmiStoreStr("guomei");
        System.out.println(str.toString());
        System.out.println(JSONObject.toJSONString(str));
    }

java中toJSONString和toString tostring tojsonstring_动态生成

看起来好像没有什么问题,别急,我们修改下我们刚才准备的bean

public class YunmiStoreStr {
    private String gome;

    public YunmiStoreStr(String gome) {
        this.gome = gome;
    }

    @Override
    public String toString() {
        return "YunmiStoreStr{" +
                "gome='" + gome + '\'' +
                '}';
    }
}

这个时候我们再次打印试试看

java中toJSONString和toString tostring tojsonstring_java_02

为啥fastJson没了,gson还在,接下来我们从源码扒一扒为什么

首先我们先看看toJsonString拿着我们的对象去干啥了

首先内部先为我们创建一个JSONSerializer对象讲我们的对象进行write操作 以下为JSONSerializer的write方法 源自:---JSONSerializer public final void write(Object object) {     if(object == null) {         this.out.writeNull();     } else {         Class<?> clazz = object.getClass();         ObjectSerializer writer = this.getObjectWriter(clazz);         try {             writer.write(this, object, (Object)null, (Type)null);         } catch (IOException var5) {             throw new JSONException(var5.getMessage(), var5);         }     } }

 

由一个全局的SerializeConfig通过class全限定名获取ObjectSerializer

这个SerializeConfig里放的是什么呢?从getObjectWriter这个方法后面

java中toJSONString和toString tostring tojsonstring_fastjson_03

可以知道存放就是一些常用的类型

这时候我们的对象并未命中这时会通过SerializeConfig的createJavaBeanSerializer帮我们做一份以我们对象的全限定名为key,value为我们对象的ObjectSerializer存储以后我们再进行toJsonString时就不需要再重复这种操作

我们继续深入看看这个createJavaBeanSerializer会做哪些工作

public ObjectSerializer createJavaBeanSerializer(Class<?> clazz) { if(!Modifier.isPublic(clazz.getModifiers())) {     return new JavaBeanSerializer(clazz); } else {     boolean asm = this.asm;     if(asm && this.asmFactory.isExternalClass(clazz) || clazz == Serializable.class || clazz == Object.class) {         asm = false;     }     JSONType annotation = (JSONType)clazz.getAnnotation(JSONType.class);     if(annotation != null && !annotation.asm()) {         asm = false;     }     if(asm) {         try {             return this.createASMSerializer(clazz);         } catch (ClassCastException var4) {             return new JavaBeanSerializer(clazz);         } catch (Throwable var5) {             throw new JSONException("create asm serializer error, class " + clazz, var5);         }     } else {         return new JavaBeanSerializer(clazz);     } } }

先看第一句

!Modifier.isPublic(clazz.getModifiers())

从Modifier这个类的简介我们可以看出``

The Modifier class provides methods and constants to decode class and member access modifiers.

即: 这句的意思我们的class是否不是public的

有兴趣的童鞋可以尝试将bean改为default类型或其他 进行尝试会进入该条件内

言归正传,这时我们进入createASMSerializer看看,createASMSerializer会通过ASMSerializerFactory的createJavaBeanSerializer来操作

public ObjectSerializer createJavaBeanSerializer(Class<?> clazz, Map<String, String> aliasMap) throws Exception { if(clazz.isPrimitive()) {     throw new JSONException("unsupportd class " + clazz.getName()); } else {     List<FieldInfo> getters = TypeUtils.computeGetters(clazz, aliasMap, false);     String className = this.getGenClassName(clazz);     ClassWriter cw = new ClassWriter();     cw.visit(49, 33, className, "java/lang/Object", new String[]{"com/alibaba/fastjson/serializer/ObjectSerializer"});     FieldVisitor fw = cw.visitField(2, "nature", ASMUtils.getDesc(JavaBeanSerializer.class));     fw.visitEnd();     Iterator i$ = getters.iterator();     while(i$.hasNext()) {         FieldInfo fieldInfo = (FieldInfo)i$.next();         FieldVisitor fw = cw.visitField(1, fieldInfo.getName() + "_asm_fieldPrefix", "Ljava/lang/reflect/Type;");         fw.visitEnd();         fw = cw.visitField(1, fieldInfo.getName() + "_asm_fieldType", "Ljava/lang/reflect/Type;");         fw.visitEnd();     }     ...此处省略多行代码 为asm动态生成的一些代码...     byte[] code = cw.toByteArray();     Class<?> exampleClass = this.classLoader.defineClassPublic(className, code, 0, code.length);     Object instance = exampleClass.newInstance();     return (ObjectSerializer)instance; } }

这个方法首先先判断clazz是否是基本类型,若为基本类型则抛出异常,否则再进行操作(由于computeGetters这个方法较长此处不全贴,仅贴部分代码)

  • TypeUtils.computeGetters先 clazz.getMethods();获取方法(由于我们的问题不在这所以就先跨过去)
    注意此处两个判断:
  • if(methodName.startsWith("get"))
  • if(methodName.startsWith("is") && methodName.length() >= 3)
    通过这两个筛选对我们的成员进行获取属性名和方法名
    筛选完方法再通过clazz.getFields()拿到所有成员

通过clazz.getFields()获取不到我们的private成员

java中toJSONString和toString tostring tojsonstring_java_04

java中toJSONString和toString tostring tojsonstring_fastjson_05

至此我们的为什么我们打印的json什么都没的问题已经得到答案

那么假设已经取到了我们的成员变量等在哪里完成json转换的呢?

这里需要一些其他的知识点有兴趣的童鞋可以了解下ASM框架,是一个Java字节码操作的框架,能够以二进制形式修改已有类或者动态生成类,有些童鞋可能已经了解过Javassist,相比于javassist而言,ASM的性能更高,但是入门相对来说难度稍微高点

言归正传

从刚才createJavaBeanSerializer方法中我们可以看到ASMSerializerFactory对我们的class进行了一系列操作,我们看到mw,cw其实此处就是帮我们动态生成了一份实现了ObjectSerializer接口的一个类

public interface ObjectSerializer {
    void write(JSONSerializer var1, Object var2, Object var3, Type var4) throws IOException;
}

该接口声明了write方法,该生成的动态类内部实现了该方法

我们再回到toJSONString方法内调用JSONSerializer的write方法

 

注意getObjectWriter方法就是将动态生成的类创建的对象返回,执行生成类内部实现了的write方法,我将该动态类的write方法贴在如下:(由于是动态生成class文件,所以此处做了一部分修改用以导出生成的class文件)

我们通过模拟ASMSerializerFactory使其将动态生成的类导出来

然后模拟write操作(模拟代码如下):

ObjectSerializer writer = new Serializer_1();
        SerializeWriter out = new SerializeWriter();
        JSONSerializer serializer = new JSONSerializer(out);
        SerializerFeature[] features = new SerializerFeature[0];
        SerializerFeature[] arr$ = features;
        int len$ = features.length;

        for(int i$ = 0; i$ < len$; ++i$) {
            SerializerFeature feature = arr$[i$];
            serializer.config(feature, true);
        }

        try {
            writer.write(serializer,str,null,null);
        } catch (IOException e) {
            e.printStackTrace();
        }

我们进入生成类的write方法:

java中toJSONString和toString tostring tojsonstring_json_06

一进来就是四重判断

  1. 是否按照字段名称排序后输出
  2. 结果是否格式化
  3. 是否包含引用类型
  4. 是否作为数组输出

最后

java中toJSONString和toString tostring tojsonstring_fastjson_07

在此处处理json串完成整个jsonstring操作

至此toJSONString分析完毕