我正在使用java.xml.bind
- 带注释的Bean来创建XML输出格式,忽略集合如果它们为空。为此目的,相应的Getter必须如下所示:
@XmlElementWrapper(name = "titles")
@XmlElement(name = "title")
public List<XmlTitle> getTitles() {
if (titles.size() == 0) {
return null;
}
return titles;
}
这在编组期间工作正常。遗憾的是,一旦我想解组相同的XML文件,我就得到了NullpointerException
:
java.lang.NullPointerException
at com.sun.xml.bind.v2.runtime.reflect.Lister$CollectionLister.addToPack(Lister.java:305)
at com.sun.xml.bind.v2.runtime.reflect.Lister$CollectionLister.addToPack(Lister.java:269)
at com.sun.xml.bind.v2.runtime.unmarshaller.Scope.add(Scope.java:121)
at com.sun.xml.bind.v2.runtime.property.ArrayERProperty$ReceiverImpl.receive(ArrayERProperty.java:213)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.endElement(UnmarshallingContext.java:538)
at com.sun.xml.bind.v2.runtime.unmarshaller.ValidatingUnmarshaller.endElement(ValidatingUnmarshaller.java:107)
at com.sun.xml.bind.v2.runtime.unmarshaller.SAXConnector.endElement(SAXConnector.java:158)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endElement(AbstractSAXParser.java:609)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanEndElement(XMLDocumentFragmentScannerImpl.java:1782)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2973)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:606)
at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:117)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:510)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:848)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:777)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1213)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:258)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:229)
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:140)
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:123)
at org.springframework.oxm.jaxb.Jaxb2Marshaller.unmarshal(Jaxb2Marshaller.java:754)
at org.springframework.oxm.jaxb.Jaxb2Marshaller.unmarshal(Jaxb2Marshaller.java:735)
这与Getter返回null
有关。正如一些JAXB专家在Glassfish JAXB forum上解释的那样:
JAXB unmarshaller不期望类型属性的setter 清单;它只是使用x.getSomeList()。add(y)来添加另一个孩子。
我如何才能最好地解决这个难题?
答案 0 :(得分:1)
根据例外,当marschalling时,JAXB不允许列表为null
。因此,您可以创建一个包含类,而不是使用注释@XmlElementWrapper(name = "titles")
,您可以在包含的类中使用它来保存XmnlTitle
列表。如果你看起来像xjc
生成的类,你会发现这正是它处理包装列表元素的方式。
此外,JAXB会自动省略null
元素,这是您在null
size() == 0
而无法解除列表取消联系的方法
打包机:
public class XmlTitleWrapper {
private List<XmlTitle> title;
public void setTitle(List<XmlTitle> title) {
this.title = title;
}
@XmlElement(name = "title")
public List<XmlTitle> getTitle() {
if(title == null) {
title = new ArrayList<XmlTitle>();
}
return title;
}
@Override
public String toString() {
return "XmlTitleWrapper [title=" + title + "]";
}
}
容器:
@XmlRootElement
public class Container {
private XmlTitleWrapper titles;
@XmlElement(name = "titles")
public XmlTitleWrapper getTitles() {
return titles;
}
public void setTitles(XmlTitleWrapper titles) {
this.titles = titles;
}
@Override
public String toString() {
return "Container [titles=" + titles + "]";
}
}
测试:
Container c1 = new Container();
List<XmlTitle> title = Arrays.asList(new XmlTitle("A"), new XmlTitle("B"));
XmlTitleWrapper wrapper = new XmlTitleWrapper();
wrapper.setTitle(title);
c1.setTitles(wrapper);
StringWriter writer = new StringWriter();
JaxbUtil.toXML(c1, writer);
System.out.printf("%s%n", String.valueOf(writer));
这会产生:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<container>
<titles>
<title>
<value>A</value>
</title>
<title>
<value>B</value>
</title>
</titles>
</container>
如果删除设置包装器的行
c1.setTitles(wrapper);
因此将null
留在容器中,然后输出为:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<container/>
答案 1 :(得分:1)
您可以创建一个XmlAdapter,您可以在其中控制编组和解组行为。
答案 2 :(得分:0)
您可以通过实现JAXB定义的回调来解决它。使用unmarshaller回调,afterUnmarshal来清理列表。
@XmlElement (name = "title")
List<XmlTitle> theTitles = new ArrayList<XmlTitle>();
...
void afterUnmarshal(Unmarshaller aUnmarshaller, Object aParent)
{
if (requiredBooks != null)
{
Iterator<XmlTitle> iterator = theTitles.iterator();
while (iterator.hasNext())
{
XmlTitle theTitle = iterator.next();
if (null == theTitle)
{
iterator.remove();
}
}
}
}