fastJson的toJSONString解读

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));
    }

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

public class YunmiStoreStr {
    private String gome;
​
    public YunmiStoreStr(String gome) {
        this.gome = gome;
    }
​
    @Override
    public String toString() {
        return "YunmiStoreStr{" +
                "gome='" + gome + '\'' +
                '}';
    }
}

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

为啥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这个方法后面

fastJson的toJSONString解读_第1张图片

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

这时候我们的对象并未命中这时会通过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 aliasMap) throws Exception {
 if(clazz.isPrimitive()) {
     throw new JSONException("unsupportd class " + clazz.getName());
 } else {
     List 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成员

fastJson的toJSONString解读_第2张图片

fastJson的toJSONString解读_第3张图片

至此我们的为什么我们打印的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方法:

fastJson的toJSONString解读_第4张图片

一进来就是四重判断

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

最后

fastJson的toJSONString解读_第5张图片

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

至此toJSONString分析完毕

你可能感兴趣的:(java)