前言
文章会参考很多其他文章的内容,记个笔记。
FASTJSON
fastjson 组件是 阿里巴巴开发的序列化与 反序列化组件。
fastjson 组件 在反序列化不可信数据时会导致远程代码执行。
POJO
POJO是 Plain OrdinaryJava Object 的缩写 ,但是它通指没有使用 Entity Beans 的普通 java 对象,可以把 POJO 作为支持业务逻辑的协助类
用 来实现JAVA POJO对象 与JSON 字符串的互相转换,比如:
User user = new User();
user.setUserName("李四");
user.setAge(24);
String userJson = JSON.toJSONString(user);
将其 序列化的结果为:
{"age":24,"userName":"李四"}
以上将对象转换为 JSON 字符串的操作 称之为 序列化 ,反之,将JSON字符串实例化成 JAVA POJO 对象的操作 即称之为 反序列化。
Java 反序列化机制
简单介绍 序列化 和反序列化工具类:
ObjectInputStream和ObjectOutputStream
序列化
User user = new User();
user.setName("李四");
user.setSex("M");
ObjectOutputStream oo = new ObjectOutputStream(new FileOutputStream(new File("User.txt")));
oo.writeObject(user);
反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("User.txt")));
User user1 = (User) ois.readObject();
System.out.println(user1.getName() + ":" + user1.getSex());
序列化需要调用ObjectOutputStream的writeObject方法,反序列化需要调用ObjectInputStream的readObject方法。
输出结果:
也就是执行了以下:
User writeObject
User readObject
User readResolve
李四:M
fastjson 反序列化机制
添加依赖:
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.23</version>
</dependency>
</dependencies>
案例1
标准POJO类定义如下,有userName和age两个属性,还有一些构造函数。
package fastjson;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
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) throws Exception{
System.out.println("setAge");
this.age = age;
}
public void setTest(int i){
System.out.println("setTest");
}
public static void test1() throws Exception {
Student student = new Student();
student.setAge(18);
student.setName("snowy");
System.out.println("====================");
String jsonString1 = JSON.toJSONString(student);
System.out.println("====================");
String jsonString2 = JSON.toJSONString(student, SerializerFeature.WriteClassName);
System.out.println(jsonString1);
System.out.println(jsonString2);
}
public static void test2()throws Exception{
String jsonString1 = "{\"age\":18,\"name\":\"snowy\"}\n";
String jsonString2 = "{\"@type\":\"fastjson.Student\",\"age\":18,\"name\":\"snowy\"}\n";
System.out.println(JSON.parse(jsonString1));
System.out.println("======================");
System.out.println(JSON.parse(jsonString2));
System.out.println("======================");
System.out.println(JSON.parseObject(jsonString1));
System.out.println("======================");
System.out.println(JSON.parseObject(jsonString2));
System.out.println("======================");
}
public static void main(String[] args) throws Exception {
test1();
//test2();
}
}
结果:
可以看到, 调用JSON.toJSONString 的话(也就是序列化了),会自动调用对应的 getter
其次 若是加上 SerializerFeature.WriteClassName,则返回的内容除属性值外,还会加上@type 字段 指明当前类。
实例2:
接下来 看看test 2,将 JSON字符串转换成对象。
String jsonString1 = "{\"age\":18,\"name\":\"snowy\"}\n";
String jsonString2 = "{\"@type\":\"fastjson.Student\",\"age\":18,\"name\":\"snowy\"}\n";
System.out.println(JSON.parse(jsonString1));
System.out.println("======================");
System.out.println(JSON.parse(jsonString2));
System.out.println("======================");
System.out.println(JSON.parseObject(jsonString1));
System.out.println("======================");
System.out.println(JSON.parseObject(jsonString2));
System.out.println("======================");
结果:
{"name":"snowy","age":18}
======================
构造函数
setAge
setName
fastjson.Student@4629104a
======================
{"name":"snowy","age":18}
======================
构造函数
setAge
setName
getAge
getName
{"name":"snowy","age":18}
======================
可以看到,不加上 @type 指明类时,时得不到类对象的。
当 加上 @type 字段 的字符串进行传唤后,不仅能得到类对象, parse 会调用 对应的 setter,
而 parseObject 会调用两者 也就是 setter 和 getter
这个 @type 的方式 也叫做 autotype:
autotype 是 Fastjson 中的一个重要机制,粗略来说就是用于设置能否将 JSON 反序列化成对象。
set开头的方法要求:
- 方法名长度大于4且以set开头,且第四个字母要是大写
- 非静态方法
- 返回类型为void或当前类
- 参数个数为1个
- get开头的方法要求:
方法名长度大于等于4
- 非静态方法
- 以get开头且第4个字母为大写
- 无传入参数
- 返回值类型继承自 Collection 或 Map 或 AtomicBoolean 或 AtomicInteger 或 AtomicLon
JdbcRowSetImpl链结合JNDI注入
fastjson<1.2.24
在上边 案例 1 中 自动调用 getter 时,应该可以联想到 Commons-Beanutils中动态调用 getter 的方法。
如 Commons-Beanutils 里 PropertyUtils.getProperty 传入 name,他会自动在前面加上 get,然后将 n 转为大写,即调用 getName。 所以,这里如果传入 outputProperties 时,他会自动调用getOutputProperties ,所以这里也可以用这种方式来调用关键的两个方法 :setDataSourceName()
和setAutoCommit()
public void setAutoCommit(boolean var1) throws SQLException {
if (this.conn != null) {
this.conn.setAutoCommit(var1);
} else {
this.conn = this.connect();
this.conn.setAutoCommit(var1);
}
}
如果 这里的 this.conn == null 会调用 本类的 this.connect()
private Connection connect() throws SQLException {
if (this.conn != null) {
return this.conn;
} else if (this.getDataSourceName() != null) {
try {
InitialContext var1 = new InitialContext();
DataSource var2 = (DataSource)var1.lookup(this.getDataSourceName());
connect() 中 如果 this.getDataSourceName() != null 则会调用 lo