Fastjson基础

一. 简介

FastJson 是一种高性能的 Java JSON 解析库。可以将 Java 对象转换为 JSON 格式(序列化),当然它也可以将 JSON 字符串转换为 Java 对象(反序列化)。

提供两个主要接口 JSON.toJSONString 和 JSON.parseObject/JSON.parse 来分别实现序列化和反序列化操作。

二. 代码执行原理

首先写一个学生类 Student

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package org.example;

import java.util.Map;

public class Student {
private String name;
private int age;

public Student() {
System.out.println("构造函数");
}

public String getName() {
System.out.println("getName");
return name;
}

public void setName(String name) {
System.out.println("setName");
this.name = name;
}
public int getAge() {
System.out.println("getAge");
return age;
}
public void setAge(int age) {
System.out.println("setAge");
this.age = age;
}

}

序列化与反序列化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package org.example;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;


public class Json {
public static void main(String[] args) {
Student student = new Student();
student.setName("Fastjson");
String jsonString = JSON.toJSONString(student, SerializerFeature.WriteClassName);
System.out.println(jsonString);

//反序列化
Student student2=JSON.parseObject(jsonString, Student.class);
//或者:Object student2 = JSON.parse(jsonString);
System.out.println(student2);


}
}

JSON.toJSONString()序列化设置了一个属性值SerializerFeature.WriteClassName,设置它之后将会增加一个<font style="color:rgb(51, 51, 51);">@type字段</font>,会写上被序列化的类名指定被序列化的类。在序列化的时候把原始类型记录下来,这样反序列化的时候就能区分出原始类型了

tips:反序列化函数,parseObject(s)返回 jsonObject,parse(s)也是一个反序列化的静态方法它返回原本的类型。parseObject(s,xxxxx),传入第二个参数为指定的原本类型时,也可返回原本类型

利用

利用处:反序列化函数 paresObject(s)的参数没有传原本类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package org.example;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;


public class JSONUser {
public static void main(String[] args) {
String s ="{\"@type\":\"org.example.Student\",\"age\":18,\"name\":\"Fastjson\"}";
JSONObject jsonObject = JSON.parseObject(s);
System.out.println(jsonObject);
}
}



可以看到向上面所说 parseObject 输出反序列化的结果是 json 形式,该过程中 Fastjson 底层会处理将字符串根据@type 字段指定的的的类进行解析为对应的 java 对象,并调用方法。

调用流程:

Student 类加了 getMap,方法,后面调试部分看它的作用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package org.example;

import java.util.Map;

public class Student {
private String name;
private int age;
private Map map;

public Student() {
System.out.println("构造函数");
}

public String getName() {
System.out.println("getName");
return name;
}

public void setName(String name) {
System.out.println("setName");
this.name = name;
}
public int getAge() {
System.out.println("getAge");
return age;
}
public void setAge(int age) {
System.out.println("setAge");
this.age = age;
}
public Map getMap () {
System.out.println("getMap");
return map;
}

}

#toJSONString 断点跟进

实例化 SerializeWriter 就已经进行序列化了,并且注意此时静态变量 DEFAULTT_TYPE_KEY 为@type,标记反序列化的指定类

然后反序列化方法处断点调试,调用 parse 之后进行返回,parse 是静态的一个方法。返回后进行判断和转化。JSONObject 实现 Map 接口

1
2
3
4
public static JSONObject parseObject(String text) {
Object obj = parse(text);
return obj instanceof JSONObject ? (JSONObject)obj : (JSONObject)toJSON(obj);
}

跟着静态的方法走来到这,先实例化一个默认解析器对象,调用 parse()

1
2
3
4
5
6
7
8
9
10
11
public static Object parse(String text, int features) {
if (text == null) {
return null;
} else {
DefaultJSONParser parser = new DefaultJSONParser(text, ParserConfig.getGlobalInstance(), features);
Object value = parser.parse();
parser.handleResovleTask(value);
parser.close();
return value;
}
}

进去 parse,由 switch 走到这里,实例化 JSON 对象并传参进接下来的核心逻辑 parseObject()

DefaultJSONParser.parseObject()

里面先对 key 进行处理,检测到有@type,进入 if 逻辑,进行类加载,使用 App 类加载器进行加载指定 type 类,把他放到缓存中,然后返回如下图

接着回到方法 DefaultJSONParser.parseObject()里面,从内存中获取 java 反序列化解析器,后会调用解析器的反序列化方法

先着获取解析器的方法 getDeserializer()【这个方法也是一个套娃的入口,接下来后面是为了解决调试问题,虽然后面有点乱,但涉及到调用哪一些构造函数 setter,getter 方法的逻辑,跟一遍看一下】后面的都是为了获得这个解析器,走到这里,调用 creatJavaBeanDeserializer 方法。

creatJavaBeanDeserializer 方法,中 asmEnable 是 java 底层记录动态创建类,动态加载的。asmEnable 默认开关是 true,在下面判断代码的一些情况下会被关掉

判断完之后会调用一个重要的方法 build

在 build 方法中会获取指定类的构造函数,setter 方法,还有一些特殊情况下的 getter(只有 getter 没有 setter,且满足返回类型为集合,Map 或 Atomic)

来到三个遍历这里(它是重要的逻辑),先看遍历 method 他反射遍历了所有的 public 方法,setter,getter,还有 Object 方法,但第一个 for 循环只将 setter 方法存进 list 中,反序列化是找 setter,序列化是找 getter。每个遍历最后来到 add 这里,进入它的参数 FieldInfo 构造函数。

进入构造方法,看影响逻辑的这一段,如果参数的长度不为 1 的话,就会进入到 else 的逻辑改变字段 getOnly 的值,如下图,这里的作用后续用到

然后接着 method 的遍历这里,add 的逻辑就是放到 list 中,不跟进去看了。遍历完就获取了所有的 setter。

注意一下第一个遍历 setter 方法,是需要参数长度为 1,才能将方法 add 进去,所以如果后需要改变 getOnly 的值时,第一个 for 循环用不了

接着第二个 for 循环该遍历 filed 来获取所有的 public,非 static/final 变量。而我们指定的 Student 是我们自己写的没有 public 字段。

下一个遍历里面:当有些类没有 setter 但有 getter,并且方法满足返回值方法名长度等一些条件,也就是刚刚添加的 getMap()方法会进入下面的 if,之后将 getter add 进去,保证这种类 getter 方法能反序列化成功。

走完三个遍历,调构造器,将遍历后 add 的 List 传进去返回 JavaBeanInfo

可以看到 JavaBeanInfo 赋值给 beanInfo 的属性值,同时有对应的 setter 方法

build 方法返回结果了,接着继续 creatJavaBeandeserializer 方法的逻辑

下面还有机会将开关变为 false,注意一下这里的机会,等一下会修改

机会给完了之后,开关还为 true 的话,会进入到这里创建一个临时的 JavaBeanDeserializer

返回的就是这个临时的解析器。然后问题出现在了这里,

回到我们套娃的起点,用临时解析器调用 deserialize,是不能调试的

所以要开关变为 false,进入 if,就可以调了

这里就接上了之前说的修改 getOnly 的作用,回看就是 build 返回的对象字段 getOnly 可以将开关设为 false。

build 这里改变代码走向的点就是在上面提到的第三个 for 循环遍历时的 getMap(),该方法满足限制的条件。之后调用 add 方法,当执行到它的参数 FieldInfo 构造函数时,就像前文所说的满足条件后 getOnly 就可以设置成 true,这样只要这里发生改变,后续代码走向就不会创建临时的解析器,就能进行调试。

上面说这么多就是为了解决调试问题,并且过一下重要逻辑,三个 for 循环。

之后就能进入到对应的反序列化方法 JavaBeanDeserializer.deserialze 中这里面流程也·挺乱的不细看了,就是会反射调用构造函数和 setter 方法,特殊的 getter 方法。之后返回的 parseObject()方法中,调用 toJSON 会调用 getter 方法。

可以看到反序列化加入了 map 之后,getMap 方法就调用了两次,一次是他作为为特殊的 getter,并且满足返回条件那些被调用,另一次是 toJSON 进行调用

整个调用流程就是这样

简单 POC

setter 方法注意参数长度为 1,并且 json 的 key 匹配的是 set 后面的内容,与属性无关。

1
2
3
4
5
6
public class Test {
public void setCmd(String cmd) throws IOException {
Runtime.getRuntime().exec(cmd);
}
}

总结

总结下来

Fastjson 反序列化函数首先对字符串进行解析,检测到含有@Type 字段就将它看作 java 对象进行操作,获取解析器,调它所对应的反序列化方法。

parsonObject == parse+toJSON()


反序列化用方法 parseObject 会调用:

构造方法

  • 字段映射的 setter(非 static,参数 1 个,返回值为 void 或自身值)

  • 字段有 getter 没 setter,调 getter 方法(非 static,无参数,返回类型是 Collection、Map、AtomicBoolean、AtomicInteger、AtomicLong 之一)

  • getter 方法。(非 static,无参数,返回类型是 Collection、Map、AtomicBoolean、AtomicInteger、AtomicLong 之一)

反序列化用方法 parse 会调用:

构造方法

  • 字段映射的 setter(非 static,参数 1 个,返回值为 void 或自身值)

  • 字段有 getter 没 setter,调 getter 方法(非 static,无参数,返回类型是 Collection、Map、AtomicBoolean、AtomicInteger、AtomicLong 之一)


Fastjson基础
https://bxhhf.github.io/2025/10/23/yuque-hexo-post/Fastjson基础/
作者
bxhhf
发布于
2025年10月23日
许可协议