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;}
@Overridepublic 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这个方法后面
可以知道存放就是一些常用的类型
这时候我们的对象并未命中这时会通过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成员
而
至此我们的为什么我们打印的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方法:
一进来就是四重判断
- 是否按照字段名称排序后输出
- 结果是否格式化
- 是否包含引用类型
- 是否作为数组输出
最后
在此处处理json串完成整个jsonstring操作
至此toJSONString分析完毕