在 Setter 中复制列表会使 XML Unmarshaller 无法工作
Copying List in Setter makes XML Unmarshaller not work
我有一个这样的 DataBean:
@XmlRootElement
public class DataBean {
private List<String> data;
@XmlElement(name = "data")
public List<String> getData() {
return data != null ? Collections.unmodifiableList(data) : null;
}
public void setData(List<String> data) {
data = new ArrayList<>(data);
data.sort(Comparator.naturalOrder());
this.data = data;
}
}
在DataBean 内部,列表必须排序,否则DataBean 在我的域中不可用。为了避免副作用,我复制了setter中的列表,然后对它进行排序。
编组此 bean 工作正常,但在解组时,数据列表为空(非空)。下面是一些代码来演示:
public class XmlTester {
public static void main(String[] args) {
List<String> data = Arrays.asList("one", "two", "three", "four");
DataBean dataBean = new DataBean();
dataBean.setData(data);
System.out.printf("Data in original bean: %s%n%n", dataBean.getData().toString());
try {
String xmlString = serialize(dataBean);
System.out.printf("XML:%n%s%n", xmlString);
DataBean deserializedDataBean = deserialize(xmlString);
System.out.printf("Data in deserialized bean: %s%n%n", deserializedDataBean.getData().toString());
} catch (JAXBException e) {
e.printStackTrace();
}
}
private static String serialize(DataBean dataBean) throws JAXBException {
StringWriter w = new StringWriter();
JAXBContext jc = JAXBContext.newInstance(DataBean.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(dataBean, w);
return w.toString();
}
private static DataBean deserialize(String xmlString) throws JAXBException {
JAXBContext context = JAXBContext.newInstance(DataBean.class);
Unmarshaller um = context.createUnmarshaller();
return (DataBean) um.unmarshal(new StringReader(xmlString));
}
}
这会产生以下输出:
Data in original bean: [four, one, three, two]
XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<dataBean>
<data>four</data>
<data>one</data>
<data>three</data>
<data>two</data>
</dataBean>
Data in deserialized bean: []
如果我从 bean 中的 setter 中删除行 data = new ArrayList<>(data);
,解组就像一个魅力,所以复制操作似乎是问题所在。
为什么复制使反序列化bean中的列表为空,我可以在不删除复制操作的情况下解决这个问题吗?
当然,我可以改为测试数据是否已排序,如果未排序则抛出 IllegalArgumentException,但我更愿意在 setter.
中对副本进行排序
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement
public class DataBean {
@XmlElement(name = "data")
private List<String> data;
public List<String> getData() {
return data != null ? Collections.unmodifiableList(data) : null;
}
public void setData(List<String> data) {
data = new ArrayList<>(data);
data.sort(Comparator.naturalOrder());
this.data = data;
}
}
Data in original bean: [four, one, three, two]
XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<dataBean>
<data>four</data>
<data>one</data>
<data>three</data>
<data>two</data>
</dataBean>
Data in deserialized bean: [four, one, three, two]
我有一个这样的 DataBean:
@XmlRootElement
public class DataBean {
private List<String> data;
@XmlElement(name = "data")
public List<String> getData() {
return data != null ? Collections.unmodifiableList(data) : null;
}
public void setData(List<String> data) {
data = new ArrayList<>(data);
data.sort(Comparator.naturalOrder());
this.data = data;
}
}
在DataBean 内部,列表必须排序,否则DataBean 在我的域中不可用。为了避免副作用,我复制了setter中的列表,然后对它进行排序。
编组此 bean 工作正常,但在解组时,数据列表为空(非空)。下面是一些代码来演示:
public class XmlTester {
public static void main(String[] args) {
List<String> data = Arrays.asList("one", "two", "three", "four");
DataBean dataBean = new DataBean();
dataBean.setData(data);
System.out.printf("Data in original bean: %s%n%n", dataBean.getData().toString());
try {
String xmlString = serialize(dataBean);
System.out.printf("XML:%n%s%n", xmlString);
DataBean deserializedDataBean = deserialize(xmlString);
System.out.printf("Data in deserialized bean: %s%n%n", deserializedDataBean.getData().toString());
} catch (JAXBException e) {
e.printStackTrace();
}
}
private static String serialize(DataBean dataBean) throws JAXBException {
StringWriter w = new StringWriter();
JAXBContext jc = JAXBContext.newInstance(DataBean.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(dataBean, w);
return w.toString();
}
private static DataBean deserialize(String xmlString) throws JAXBException {
JAXBContext context = JAXBContext.newInstance(DataBean.class);
Unmarshaller um = context.createUnmarshaller();
return (DataBean) um.unmarshal(new StringReader(xmlString));
}
}
这会产生以下输出:
Data in original bean: [four, one, three, two]
XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<dataBean>
<data>four</data>
<data>one</data>
<data>three</data>
<data>two</data>
</dataBean>
Data in deserialized bean: []
如果我从 bean 中的 setter 中删除行 data = new ArrayList<>(data);
,解组就像一个魅力,所以复制操作似乎是问题所在。
为什么复制使反序列化bean中的列表为空,我可以在不删除复制操作的情况下解决这个问题吗?
当然,我可以改为测试数据是否已排序,如果未排序则抛出 IllegalArgumentException,但我更愿意在 setter.
中对副本进行排序@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement
public class DataBean {
@XmlElement(name = "data")
private List<String> data;
public List<String> getData() {
return data != null ? Collections.unmodifiableList(data) : null;
}
public void setData(List<String> data) {
data = new ArrayList<>(data);
data.sort(Comparator.naturalOrder());
this.data = data;
}
}
Data in original bean: [four, one, three, two]
XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<dataBean>
<data>four</data>
<data>one</data>
<data>three</data>
<data>two</data>
</dataBean>
Data in deserialized bean: [four, one, three, two]