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方法:

一进来就是四重判断

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

最后

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

至此toJSONString分析完毕

fastJson的toJSONString解读相关推荐

  1. fastjson使用toJSONString时null值不序列化问题

    问题描述: 在使用fastjson调用 JSON.toJSONString(obj); 方法将对象转换为json字符串时,如果对象obj的属性字段有值为null时,该属性字段不会被序列化. 比如:定义 ...

  2. fastjson JSONObject.toJSONString 出现 $ref: $.的解决办法(重复引用)

    首先,fastjson作为一款序列化引擎,不可避免的会遇到循环引用的问题,为了避免StackOverflowError异常,fastjson会对引用进行检测. 如果检测到存在重复/循环引用的情况,fa ...

  3. fastjson toJSONString 出错 Positioned Update not supported

    问题 JSON.toJSONString(this) 出错: com.alibaba.fastjson.JSONException: write javaBean error, fastjson ve ...

  4. Gson与FastJson比较

    一. 简介和优劣 1.Google的Gson Gson是目前功能最全的Json解析神器,Gson当初是为因应Google公司内部需求而由Google自行研发而来,但自从在2008年五月公开发布第一版后 ...

  5. 【Android 应用开发】 FastJson 使用详解

    博客地址 : http://blog.csdn.net/shulianghan/article/details/41011605 fastjson 源码地址 : -- GitHub : https:/ ...

  6. java异常 json,记一个toJSONString异常

    异常 java.io.FileNotFoundException: Byte array resource [resource loaded from byte array] cannot be re ...

  7. fastjson导致的OOM

    大家好,我是烤鸭: 今天又遇到OOM了,原因在于 fastjson 的 toJSONString. 这是线上的报错信息. 将这个 TotalLoanDTO 对象 toJSONString 导致的OOM ...

  8. fastjson--JSON.toJSONString(OBJ) 报错

    这两天在写用jQuery简化Ajax的时候,使用json来传输数据,老师推荐用阿里爸爸的fastjson,说官方提供的都是坑,于是乎我便down下来,开始了苦逼的一晚. String json_str ...

  9. java中float、double和BigDecimal的精度问题(fastjson、Jackson以及实例化的方式)

    java中float.double和BigDecimal的精度问题(fastjson.Jackson以及实例化的方式): 问题描述 java中如果使用float或double类型的数据初始化BigDe ...

最新文章

  1. java g1 gc ref proc_java – 针对sparc T4 8核的正确G1 GC调优
  2. O2O业务都跳不出这五大领域
  3. unix环境高级编程-进程间通信
  4. Docker常用命令(docker快捷键)海康docker命令 LY
  5. 转 10 个最佳的 Node.js 的 MVC 框架
  6. Developer FAQ: Building | 开发人员常遇到的问题:构建
  7. PHP怎么输入表达式,PHP: 表达式 - Manual
  8. 转-Redis AOF 持久化详解
  9. python编写年金终值函数_看零件图的标题栏可了解()
  10. python读压缩文件内容_使用Python读写及压缩和解压缩文件的示例
  11. 关于vhr项目部署所遇到的问题总结,Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin
  12. sql2012,返回数据多时不走索引
  13. gateway中的局部过滤器_SpringCloud系列Gateway:过滤器总结
  14. Linux之postfix邮件服务器搭建
  15. VEH+硬件断点实现无痕HOOK
  16. Linux进程虚拟内存大 性能,Linux进程分析(一) 虚拟内存和物理内存
  17. book--Unix Linux大学教程
  18. 响铃:社交型流量平台,为何线上平台都扎堆去线下造节
  19. 【PLM—1】——2019-NAACL-Bert
  20. Lazada代运营分享—Lazada新手运营快速提升流量交易额的三大核心技巧

热门文章

  1. js 转义字符及URI编码与解码
  2. 悲喜一瞬间,此悲伤非彼悲伤:伤感日志
  3. EasyX的安装与使用详细教程
  4. Python读取和保存GIF图片
  5. 长大后的你,是否还记住你的初心?
  6. 「NOIP2016」天天爱跑步
  7. 【QML】QML性能优化 | 3D场景优化
  8. lol八月那服务器有无限火力,英雄联盟无限火力8月开启时间 2021年8月无限火力时间...
  9. 最新的Python爬取淘宝评价的教程
  10. 【mac】「终端查看完整命令记录」「提示软件已损坏,无法打开」「sip~」「Vcsa安装」「errno 30」「E325」