fastJson的toJSONString解读

news/2024/11/8 0:41:11/

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分析完毕


http://www.ppmy.cn/news/356676.html

相关文章

媒体查询@media

media可以针对不同的媒体类型(包括显示器、便携设备、电视机&#xff0c;等等)设置不同的样式规则&#xff0c;CSS3 根据设置自适应显示。 1.使用方法: media 多媒体类型 and (条件) and (条件)... ①多媒体类型: all用于所有多媒体类型设备 print用于打印机 screen用于电脑…

@media媒体查询

media媒体查询 媒体查询&#xff08;media Query&#xff09;是CSS3新语法 使用 media 查询&#xff0c;可以针对不同的媒体类型定义不同的样式media 可以针对不同的屏幕尺寸设置不同的样式当你重置浏览器大小的过程中&#xff0c;页面也会根据浏览器的宽度和高度出行渲染页面目…

MEC架构

文章目录 MEC架构MEC参考架构MEC host&#xff1a;MEC platformMEC applicationMEC 系统级管理Multi-access edge orchestratorOperations Support System (OSS)User application lifecycle management proxy MEC主机级管理MEC platform managerVirtualisation infrastructure …

如果没有发现美的眼睛&#xff0c;去再远的地方也没有用&#xff01;

字符集gb2312转utf8(用spool)

gb2312转到utf8 spool出来并用iconv转到utf8 #!/bin/bash for i in cat table.txt do /opt/oracle10g/u01/bin/sqlplus -s guomei/xyzmn << EOF set newpage 0 set linesize 10000 set pagesize 0 set und off set trimspool on set colsep, set echo off …

谷歌浏览器

引言&#xff1a;众所周知&#xff0c;一个好的浏览器可以提高我们的工作效率&#xff0c;那么今天教大家如何安装超 nice 的浏览器 —— 谷歌浏览器 文章目录 一、安装谷歌浏览器二、修改谷歌浏览器搜索引擎三、修改谷歌浏览器默认下载位置 一、安装谷歌浏览器 打开&#x1f…

pycharm配置PyQt5、Open3D、Python-pcl

只是当兴趣爱好&#xff0c;看客也不用考虑构思这样的事情是不是合理。此外也是想通过这样的一个东西把自己接触过的2D&#xff0c;3D&#xff0c;深度学习能融合到一起。时间久了&#xff0c;觉得原理性的&#xff0c;理论方面的算法内容才是最重要的&#xff0c;理解了&#…

iMeta | 原核微生物泛基因组与基因组分析平台IPGA

点击蓝字 关注我们 IPGA原核微生物泛基因组与基因组分析平台 原文链接DOI: https://doi.org/10.1002/imt2.55 研究论文 ●2022年9月14日&#xff0c;中国科学院微生物研究所史文聿和马俊才团队在iMeta在线发表了题为“IPGA: A handy integrated prokaryotes genome and pan-gen…