XMLDecode

learn

How to use it?

简单地建一个User类 并添加 setget

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
package com.xmldecode;

public class User {
private String Name;
private String Sex;
private int Age;

public User() {
System.out.println("Constructor has called");
}

public User(String name, String sex, int age) {
System.out.println("有参构造方法被调用");
this.Name = name;
this.Sex = sex;
this.Age = age;
}

public void setName(String name) {
System.out.println("setName has called");
this.Name = name;
}

public void setSex(String sex) {
System.out.println("setSex has called");
this.Sex = sex;
}

public void setAge(int age) {
System.out.println("setAge has called");
this.Age = age;
}

public int getAge() {
System.out.println("getAge has called");
return this.Age;
}

public String getSex() {
System.out.println("getSex has called");
return this.Sex;
}

public String getName() {
System.out.println("getName has called");
return this.Name;
}

@Override
public String toString(){
return "User{" +
"Name='" + Name + "'" +
", Sex='" + Sex + "'" +
", Age=" + Age +
"}";
}
}

来encode一下

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
package com.xmldecode;

import java.beans.XMLEncoder;
import java.io.BufferedOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;

public class testDecode {

public static void main(String[] args) {
User user = new User();
user.setAge(20);
user.setName("b1ue0cean");
user.setSex("man");

try {
XMLEncoder encoder = new XMLEncoder(new BufferedOutputStream(
new FileOutputStream("User.xml")
));

encoder.writeObject(user);
encoder.close();
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
}

}

生成了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.8.0_202" class="java.beans.XMLDecoder">
<object class="com.xmldecode.User">
<void property="age">
<int>20</int>
</void>
<void property="name">
<string>b1ue0cean</string>
</void>
<void property="sex">
<string>man</string>
</void>
</object>
</java>

控制台

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Constructor has called
setAge has called
setName has called
setSex has called
Constructor has called
getAge has called
getAge has called
getAge has called
setAge has called
getName has called
getName has called
setName has called
getSex has called
getSex has called
setSex has called

XMLEncoder默认会在序列化时调⽤⽆参构造⽅法以及属性的 get 和 set ⽅法,并且还存在多次调⽤的情况。

XMLDecoder Deserialize

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

import java.beans.XMLDecoder;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;

public class deserialize {
public static void main(String[] args) {
XMLDecoder xmlDecoder = null;
try {
xmlDecoder = new XMLDecoder(
new BufferedInputStream(
new FileInputStream("User.xml")
)
);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
Object result = xmlDecoder.readObject();
xmlDecoder.close();
System.out.println(result);
}
}

控制台

1
2
3
4
5
Constructor has called
setAge has called
setName has called
setSex has called
User{Name='b1ue0cean', Sex='man', Age=20}

反序列化默认情况下会调⽤属性中的 set ⽅法

Analysis

主要分析一下 readObject

先弹一个计算器 o.o

1
2
3
4
5
6
7
8
9
10
<java>
<object class="java.lang.ProcessBuilder">
<array class="java.lang.String" length="1" >
<void index="0">
<string>calc</string>
</void>
</array>
<void method="start"/>
</object>
</java>

把刚才deserialize 的文件改一下就行 真弹了计算器o.o

下断点

image-20221007105846649

跟进 readObject()

image-20221007110309025

不知道为啥可以从堆栈里看,,,这个调试我也不是很熟 估计等会要找点文章学学

跟进persingComplete()

image-20221007110508400

this.Handler 为 documentHandler

image-20221007111939388

parse()

image-20221007112119165

注意看这里

image-20221007112155825

我们关注DocumentHandler的几个事件函数

image-20221007112301349

对应了com.sun.beans.decoder包中的几个类

image-20221007112536713

接着 看一下 SAX 的处理过程

image-20221007113628978

这几个 set 都要走一遍

这里y4er god中间省略了亿步。。。搞得我蒙了半天

image-20221007115726314

看调用栈可以看出 这里已经跟进了亿步的 parse

image-20221007115805974

中间跳过亿步

最后通过Expression的getValue()方法反射调用start

emmm 所以跟了这么久好像也没啥用 o.o

reference

XMLDecoder解析流程分析 - 先知社区 (aliyun.com)

https://zhuanlan.zhihu.com/p/350309128