使用循环引用序列化对象
Serializing objects with circural references
我有 2 个简单的 classes,class 代表一个公共汽车站:
import java.util.List;
public class Stop {
/**
* lines operating this stop
*/
public List<Line> lines;
public String label;
public Stop(String label, List<Line> lines) {
this.label = label;
this.lines = lines;
}
public String getLabel() {
return label;
}
public List<Line> getLines() {
return lines;
}
@Override
public String toString() {
return "Stop{" +
"label='" + label + '\'' +
'}';
}
}
和一条class象征公交线路:
import java.util.ArrayList;
import java.util.List;
public class Line {
public String label;
public int id;
public List<Stop> stops;
public Line(String label, int id, List<Stop> stops) {
this.label = label;
this.id = id;
this.stops = stops;
}
public Line(String label, int id) {
this(label, id, new ArrayList<>());
System.out.println("used second constructor");
}
public String getLabel() {
return label;
}
public int getId() {
return id;
}
public List<Stop> getStops() {
return stops;
}
@Override
public String toString() {
return "Line{" +
"label='" + label + '\'' +
", id=" + id +
", stops=" + stops +
'}';
}
}
我不想使用 java.beans.XMLEncoder 序列化这些,然后使用 XMLDecoder 反序列化。
在这种情况下(当行持有对其停止点的引用时,反之亦然),反序列化失败。解码器忽略带有附加 List<Stop> stops
参数的 Line
构造函数并使用 Line(String label, int id)
构造函数,留下此消息:
java.lang.IllegalStateException: Could not add argument to evaluated element
Continuing ...
当我完全删除 class Stop
中的操作行列表时,反序列化工作完美。
我做错了什么?
主要class:
import java.beans.DefaultPersistenceDelegate;
import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
public class App {
public static void main(String[] args) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (XMLEncoder encoder = new XMLEncoder(baos)) {
encoder.setPersistenceDelegate(Line.class, new DefaultPersistenceDelegate(new String[] {"label", "id", "stops"}));
encoder.setPersistenceDelegate(Stop.class, new DefaultPersistenceDelegate(new String[] {"label", "lines"}));
ArrayList<Stop> stops = new ArrayList<>();
stops.add(new Stop("Porte Maillot", new ArrayList<>()));
stops.add(new Stop("Auber", new ArrayList<>()));
Line line = new Line("A", 0, stops);
stops.get(0).lines.add(line);
stops.get(1).lines.add(line);
encoder.writeObject(line);
}
System.out.println("xml:");
System.out.println(baos);
try (XMLDecoder decoder = new XMLDecoder(new ByteArrayInputStream(baos.toByteArray()))){
Line line = (Line) decoder.readObject();
System.out.printf("line: %s\n", line);
}
}
}
控制台输出:
xml:
<?xml version="1.0" encoding="UTF-8"?>
<java version="15.0.1" class="java.beans.XMLDecoder">
<object class="Line" id="Line0">
<string>A</string>
<int>0</int>
<object class="java.util.ArrayList">
<void method="add">
<object class="Stop">
<string>Porte Maillot</string>
<object class="java.util.ArrayList">
<void method="add">
<object idref="Line0"/>
</void>
</object>
</object>
</void>
<void method="add">
<object class="Stop">
<string>Auber</string>
<object class="java.util.ArrayList">
<void method="add">
<object idref="Line0"/>
</void>
</object>
</object>
</void>
</object>
</object>
</java>
used second constructor
java.lang.IllegalStateException: Could not add argument to evaluated element
Continuing ...
line: Line{label='A', id=0, stops=[]}
循环引用导致 XMLDecoder 无法处理的循环序列化。使引用之一成为瞬态并在反序列化时恢复它们将解决问题,就像使用二进制序列化而不是 xml 一样。
我有 2 个简单的 classes,class 代表一个公共汽车站:
import java.util.List;
public class Stop {
/**
* lines operating this stop
*/
public List<Line> lines;
public String label;
public Stop(String label, List<Line> lines) {
this.label = label;
this.lines = lines;
}
public String getLabel() {
return label;
}
public List<Line> getLines() {
return lines;
}
@Override
public String toString() {
return "Stop{" +
"label='" + label + '\'' +
'}';
}
}
和一条class象征公交线路:
import java.util.ArrayList;
import java.util.List;
public class Line {
public String label;
public int id;
public List<Stop> stops;
public Line(String label, int id, List<Stop> stops) {
this.label = label;
this.id = id;
this.stops = stops;
}
public Line(String label, int id) {
this(label, id, new ArrayList<>());
System.out.println("used second constructor");
}
public String getLabel() {
return label;
}
public int getId() {
return id;
}
public List<Stop> getStops() {
return stops;
}
@Override
public String toString() {
return "Line{" +
"label='" + label + '\'' +
", id=" + id +
", stops=" + stops +
'}';
}
}
我不想使用 java.beans.XMLEncoder 序列化这些,然后使用 XMLDecoder 反序列化。
在这种情况下(当行持有对其停止点的引用时,反之亦然),反序列化失败。解码器忽略带有附加 List<Stop> stops
参数的 Line
构造函数并使用 Line(String label, int id)
构造函数,留下此消息:
java.lang.IllegalStateException: Could not add argument to evaluated element
Continuing ...
当我完全删除 class Stop
中的操作行列表时,反序列化工作完美。
我做错了什么?
主要class:
import java.beans.DefaultPersistenceDelegate;
import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
public class App {
public static void main(String[] args) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (XMLEncoder encoder = new XMLEncoder(baos)) {
encoder.setPersistenceDelegate(Line.class, new DefaultPersistenceDelegate(new String[] {"label", "id", "stops"}));
encoder.setPersistenceDelegate(Stop.class, new DefaultPersistenceDelegate(new String[] {"label", "lines"}));
ArrayList<Stop> stops = new ArrayList<>();
stops.add(new Stop("Porte Maillot", new ArrayList<>()));
stops.add(new Stop("Auber", new ArrayList<>()));
Line line = new Line("A", 0, stops);
stops.get(0).lines.add(line);
stops.get(1).lines.add(line);
encoder.writeObject(line);
}
System.out.println("xml:");
System.out.println(baos);
try (XMLDecoder decoder = new XMLDecoder(new ByteArrayInputStream(baos.toByteArray()))){
Line line = (Line) decoder.readObject();
System.out.printf("line: %s\n", line);
}
}
}
控制台输出:
xml:
<?xml version="1.0" encoding="UTF-8"?>
<java version="15.0.1" class="java.beans.XMLDecoder">
<object class="Line" id="Line0">
<string>A</string>
<int>0</int>
<object class="java.util.ArrayList">
<void method="add">
<object class="Stop">
<string>Porte Maillot</string>
<object class="java.util.ArrayList">
<void method="add">
<object idref="Line0"/>
</void>
</object>
</object>
</void>
<void method="add">
<object class="Stop">
<string>Auber</string>
<object class="java.util.ArrayList">
<void method="add">
<object idref="Line0"/>
</void>
</object>
</object>
</void>
</object>
</object>
</java>
used second constructor
java.lang.IllegalStateException: Could not add argument to evaluated element
Continuing ...
line: Line{label='A', id=0, stops=[]}
循环引用导致 XMLDecoder 无法处理的循环序列化。使引用之一成为瞬态并在反序列化时恢复它们将解决问题,就像使用二进制序列化而不是 xml 一样。