在 JAXB 中解组期间忽略未定义的元素引用
Ignoring undefined element references during unmarshalling in JAXB
我目前正在处理一个使用 CXF 框架请求 Web 服务的项目。
出于某些原因,我开始收到无效的 XML SOAP(缺少引用自 的 ID 的元素)响应,导致在解组到 POJO 实例期间引发异常。
示例:
XML 摘录,其中属性 ref
引用了标识符为 Person1
的元素,该元素在 XML.
中不存在
<ext:Applicant s:ref="Person1"/>
其中 ref
是 IDREF
输入 XSD 架构
<attribute name="ref" type="IDREF"/>
JAXB 抛出异常
javax.xml.ws.soap.SOAPFaultException: Unmarshalling Error: Undefined ID "Person1". ] with root cause
javax.xml.bind.UnmarshalException: Undefined ID "Person1".
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:744) ~[jaxb-impl-2.3.1.jar!/:2.3.1]
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.errorUnresolvedIDREF(UnmarshallingContext.java:795) ~[jaxb-impl-2.3.1.jar!/:2.3.1]
at com.sun.xml.bind.v2.runtime.reflect.TransducedAccessor$IDREFTransducedAccessorImpl.run(TransducedAccessor.java:330) ~[jaxb-impl-2.3.1.jar!/:2.3.1]
at...
有没有办法让 JAXB 忽略丢失的引用并解组传入的 XML 响应而不抛出异常?
请求中没有提供XML对象,具体讨论。有一个方便的解决方法可以为 JAX-B 对象创建 CustomAdapter
以确定如何 marshal
和 unmarshal
对象。
例如,下面的CustomAdapter
可以实现:
public static class CustomAdapter extends XmlAdapter<Object, Person1> {
@Override
public Object marshal(Person1 value) {
// your implementation to marshal
}
@Override
public Person1 unmarshal(Object value) {
// your implementation to unmarshal
}
}
XmlAdapter
在 javax.xml.bind.annotation.adapters.XmlAdapter
包中。
如果您使用 Person1
作为其他对象(组合)中的字段,您可以使用 @XmlJavaTypeAdapter
注释,如下所示:
@XmlJavaTypeAdapter(CustomAdapter.class)
private Person1 person1;
如果有帮助,请告诉我。
可能的解决方案是为 XMLEventReader 创建装饰器,它将过滤掉 IDREF 属性(或其他需要的属性):
public class IdRefFilteringReader implements XMLEventReader {
/**
* QName of the attribute to be removed
*/
private final static QName QNAME = new QName("http://www.w3.org/2001/XMLSchema", "ref");
/**
* Delegate XML event reader
*/
private final XMLEventReader delegate;
/**
* XML event factory
*/
private final XMLEventFactory eventFactory = XMLEventFactory.newInstance();
/**
* Constructor injects delegate
*/
public IdRefFilteringReader(XMLEventReader delegate) {
this.delegate = delegate;
}
/**
* Remove attributes with matching QName
*/
@Override
public XMLEvent nextEvent() throws XMLStreamException {
XMLEvent event = delegate.nextEvent();
if (event.isStartElement()) {
StartElement startElement = event.asStartElement();
Attribute attr = startElement.getAttributeByName(QNAME);
// if attribute is present, create new XMLEvent with same
// prefix, namespace, name and other attributes except one
// which should be removed
if(attr != null) {
String prefix = startElement.getName().getPrefix();
String uri = startElement.getName().getNamespaceURI();
String localname = startElement.getName().getLocalPart();
List<Attribute> attributes = new ArrayList<>();
startElement.getAttributes().forEachRemaining(a -> {
if(!a.getName().equals(attr.getName())) {
attributes.add(a);
}
});
return eventFactory.createStartElement(
prefix,
uri,
localname,
attributes.iterator(),
startElement.getNamespaces()
);
}
}
return event;
}
@Override
public boolean hasNext() {
return delegate.hasNext();
}
@Override
public XMLEvent peek() throws XMLStreamException {
return delegate.peek();
}
@Override
public String getElementText() throws XMLStreamException {
return delegate.getElementText();
}
@Override
public XMLEvent nextTag() throws XMLStreamException {
return delegate.nextTag();
}
@Override
public Object getProperty(String name) throws IllegalArgumentException {
return delegate.getProperty(name);
}
@Override
public void close() throws XMLStreamException {
delegate.close();
}
@Override
public Object next() {
return delegate.next();
}
}
要使用这个 reader 需要将它传递给 unmarshaller 实例,例如:
// create unmarshaller
JAXBContext ctx = JAXBContext.newInstance(Applicant.class);
Unmarshaller unmarshaller = ctx.createUnmarshaller();
// create regular XML event reader and filtered XML event reader
XMLInputFactory xif = XMLInputFactory.newInstance();
XMLEventReader reader = xif.createXMLEventReader(new StreamSource(new StringReader(xml)));
XMLEventReader filteringReader = new IdRefFilteringReader(reader);
// unmarshall XML using filtering reader
Applicant applicant = unmarshaller.unmarshal(filteringReader, Applicant.class);
我目前正在处理一个使用 CXF 框架请求 Web 服务的项目。
出于某些原因,我开始收到无效的 XML SOAP(缺少引用自 的 ID 的元素)响应,导致在解组到 POJO 实例期间引发异常。
示例:
XML 摘录,其中属性 ref
引用了标识符为 Person1
的元素,该元素在 XML.
<ext:Applicant s:ref="Person1"/>
其中 ref
是 IDREF
输入 XSD 架构
<attribute name="ref" type="IDREF"/>
JAXB 抛出异常
javax.xml.ws.soap.SOAPFaultException: Unmarshalling Error: Undefined ID "Person1". ] with root cause
javax.xml.bind.UnmarshalException: Undefined ID "Person1".
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:744) ~[jaxb-impl-2.3.1.jar!/:2.3.1]
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.errorUnresolvedIDREF(UnmarshallingContext.java:795) ~[jaxb-impl-2.3.1.jar!/:2.3.1]
at com.sun.xml.bind.v2.runtime.reflect.TransducedAccessor$IDREFTransducedAccessorImpl.run(TransducedAccessor.java:330) ~[jaxb-impl-2.3.1.jar!/:2.3.1]
at...
有没有办法让 JAXB 忽略丢失的引用并解组传入的 XML 响应而不抛出异常?
请求中没有提供XML对象,具体讨论。有一个方便的解决方法可以为 JAX-B 对象创建 CustomAdapter
以确定如何 marshal
和 unmarshal
对象。
例如,下面的CustomAdapter
可以实现:
public static class CustomAdapter extends XmlAdapter<Object, Person1> {
@Override
public Object marshal(Person1 value) {
// your implementation to marshal
}
@Override
public Person1 unmarshal(Object value) {
// your implementation to unmarshal
}
}
XmlAdapter
在 javax.xml.bind.annotation.adapters.XmlAdapter
包中。
如果您使用 Person1
作为其他对象(组合)中的字段,您可以使用 @XmlJavaTypeAdapter
注释,如下所示:
@XmlJavaTypeAdapter(CustomAdapter.class)
private Person1 person1;
如果有帮助,请告诉我。
可能的解决方案是为 XMLEventReader 创建装饰器,它将过滤掉 IDREF 属性(或其他需要的属性):
public class IdRefFilteringReader implements XMLEventReader {
/**
* QName of the attribute to be removed
*/
private final static QName QNAME = new QName("http://www.w3.org/2001/XMLSchema", "ref");
/**
* Delegate XML event reader
*/
private final XMLEventReader delegate;
/**
* XML event factory
*/
private final XMLEventFactory eventFactory = XMLEventFactory.newInstance();
/**
* Constructor injects delegate
*/
public IdRefFilteringReader(XMLEventReader delegate) {
this.delegate = delegate;
}
/**
* Remove attributes with matching QName
*/
@Override
public XMLEvent nextEvent() throws XMLStreamException {
XMLEvent event = delegate.nextEvent();
if (event.isStartElement()) {
StartElement startElement = event.asStartElement();
Attribute attr = startElement.getAttributeByName(QNAME);
// if attribute is present, create new XMLEvent with same
// prefix, namespace, name and other attributes except one
// which should be removed
if(attr != null) {
String prefix = startElement.getName().getPrefix();
String uri = startElement.getName().getNamespaceURI();
String localname = startElement.getName().getLocalPart();
List<Attribute> attributes = new ArrayList<>();
startElement.getAttributes().forEachRemaining(a -> {
if(!a.getName().equals(attr.getName())) {
attributes.add(a);
}
});
return eventFactory.createStartElement(
prefix,
uri,
localname,
attributes.iterator(),
startElement.getNamespaces()
);
}
}
return event;
}
@Override
public boolean hasNext() {
return delegate.hasNext();
}
@Override
public XMLEvent peek() throws XMLStreamException {
return delegate.peek();
}
@Override
public String getElementText() throws XMLStreamException {
return delegate.getElementText();
}
@Override
public XMLEvent nextTag() throws XMLStreamException {
return delegate.nextTag();
}
@Override
public Object getProperty(String name) throws IllegalArgumentException {
return delegate.getProperty(name);
}
@Override
public void close() throws XMLStreamException {
delegate.close();
}
@Override
public Object next() {
return delegate.next();
}
}
要使用这个 reader 需要将它传递给 unmarshaller 实例,例如:
// create unmarshaller
JAXBContext ctx = JAXBContext.newInstance(Applicant.class);
Unmarshaller unmarshaller = ctx.createUnmarshaller();
// create regular XML event reader and filtered XML event reader
XMLInputFactory xif = XMLInputFactory.newInstance();
XMLEventReader reader = xif.createXMLEventReader(new StreamSource(new StringReader(xml)));
XMLEventReader filteringReader = new IdRefFilteringReader(reader);
// unmarshall XML using filtering reader
Applicant applicant = unmarshaller.unmarshal(filteringReader, Applicant.class);