[英]Deserialize a final list attribute
假設我們有一個類測試,如:
public class Test {
private final String name;
private final List<String> list = new ArrayList<>();
public Test(String name) {
this.name = name;
}
void add(String s) {
list.add(s);
}
void print() {
System.out.println("name: " + name);
for (String s : list) {
System.out.println(" - " + s);
}
}
}
沒有XSteam的不變量
this.list != null
每次都持有。
但是,如果我們看看第四次測試
public static void main(String[] args) {
final XStream xstream = new XStream();
xstream.alias("test", Test.class);
// Serialize
final Test test1 = new Test("XYZ");
test1.add("One");
test1.add("Two");
//@formatter:off
/* name: XYZ
* - One
* - Two
*/
//@formatter:on
test1.print();
//@formatter:off
/* <test>
* <name>XYZ</name>
* <list>
* <string>One</string>
* <string>Two</string>
* </list>
* </test>
*/
//@formatter:on
System.out.println(xstream.toXML(test1));
// Deserialize with one list entry
final String xmlTest2 = "<test><name>XYZ</name><list><string>One</string></list></test>";
final Test test2 = (Test) xstream.fromXML(xmlTest2);
//@formatter:off
/* <test>
* <name>XYZ</name>
* <list>
* <string>One</string>
* </list>
* </test>
*/
//@formatter:on
test2.print();
// Deserialize with empty list
final String xmlTest3 = "<test><name>XYZ</name><list /></test>";
final Test test3 = (Test) xstream.fromXML(xmlTest3);
//@formatter:off
/* name: XYZ
*/
//@formatter:on
test3.print();
// Deserialize without list-tag
final String xmlTest4 = "<test><name>XYZ</name></test>";
final Test test4 = (Test) xstream.fromXML(xmlTest4);
//@formatter:off
/* name: XYZ
* Exception in thead ... NullPointerException
*/
//@formatter:on
test4.print();
}
我們看到一個NullPointerException,因為list
沒有初始化。
我想讓XML中的list
-element與test4類似。 我能做什么? 因為我的數據模型中有很多類與Test
類似,所以我不想為每個類編寫一個Converter
。 但是假設我會寫一個Converter
,我該如何設置最終的屬性name
?
請使用XStream Annotations和自定義Converter找到以下解決方案。
自定義轉換器是以下類:
public class ListableConverter implements Converter {
public void marshal(Object source, HierarchicalStreamWriter writer,
MarshallingContext context) {
Listable listable = (Listable) source;
writer.setValue(String.valueOf(... your marshalling logic here ...));
}
public Object unmarshal(HierarchicalStreamReader reader,
UnmarshallingContext context) {
List<String> list = new ArrayList<String>();
// your unmarshalling logic here
return list;
}
public boolean canConvert(Class type) {
return type instanceof Listable;
}
}
這是帶有Annotations的修改過的Test類:
public class Test implements Listable{
private final String name;
@XStreamConverter(ListableConverter.class)
private final List<String> list = new ArrayList<>();
public List<String> getList() {
return list;
}
public Test(String name) {
this.name = name;
}
void add(String s) {
list.add(s);
}
void print() {
System.out.println("name: " + name);
for (String s : list) {
System.out.println(" - " + s);
}
}
}
最后,用於使轉換器的接口適用於實現接口的模型中的任何類:
public interface Listable<String> {
public List<String> getList();
}
因此,例如,模型中的另一個類可能如下所示:
public class Foo implements Listable{
@XStreamConverter(ListableConverter.class)
private final List<String> anotherList = new ArrayList<>();
... omissis ...
public List<String> getList() {
return anotherList;
}
}
XStream在增強模式下使用munged構造函數(http://stackoverflow.com/questions/1426106/why-are-constructors-returned-by-reflectionfactor-newconstructorforserialization)(默認)。 您可以通過在純模式下初始化XStream來更改此行為:
XStream xstream = new XStream(new PureJavaReflectionProvider());
另一種選擇是使用getter訪問變量並實現延遲初始化。
public class Test {
private final String name;
private List<String> list;
public Test(String name) {
this.name = name;
}
void add(String s) {
list.add(s);
}
List<String> getList() {
if (list == null) {
list = new ArrayList<>();
}
return list;
}
void print() {
System.out.println("name: " + name);
for (String s : getList()) {
System.out.println(" - " + s);
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.