写在前面
平时我们在处理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 对象,那就结束了
|