我目前正在从事一个使用CXF框架请求web服务的项目。
由于某些原因,我开始收到无效的XML SOAP(缺少引用了ID的元素)响应,导致在解组到POJO实例期间抛出异常。
示例:
XML摘录,其中属性ref
引用标识符为Person1
的元素,该元素在XML中不存在。
<ext:Applicant s:ref="Person1"/>
其中ref
是XSD模式中的IDREF
类型
<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$1.run(TransducedAccessor.java:330) ~[jaxb-impl-2.3.1.jar!/:2.3.1]
at...
有没有一种方法可以让JAXB忽略缺失的引用,并且在不引发异常的情况下取消对传入XML响应的处理?
可能的解决方案是为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();
}
}
要使用此读取器,需要将其传递给解组器实例,例如:
// 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);
在请求中没有提供XML对象以更具体地讨论。有一个方便的解决方案可以为JAX-B对象创建CustomAdapter
,以确定如何列表
和散集
对象。
例如,可以实现以下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
位于XmlAdapter包javax.xml.bind.annotation.adapters.。
如果您将Person1
用作其他对象(组合)中的字段,则可以使用@XmlJavaTypeAdapter
对其进行注释,如下所示:
@XmlJavaTypeAdapter(CustomAdapter.class)
private Person1 person1;
如果有帮助,请告诉我。
当我试图使用包含名称空间的JAXB将xml转换为Java对象时,会发生错误。 示例示例:' Zeta Walnes ` 我需要忽略名称空间
问题内容: 我的架构指定了一个名称空间,但是文档没有。在JAXB解组(XML-> object)期间忽略名称空间的最简单方法是什么? 换句话说,我有 代替, 问题答案: 我相信你必须将名称空间添加到xml文档中,例如,使用SAX过滤器。 这意味着: 用一个新类定义一个ContentHandler接口,该接口将在JAXB获得它们之前拦截SAX事件。 定义一个XMLReader,它将设置内容处理程序
问题内容: 我收到一个XML响应,并且它一直在频繁更改(节点不断增加或减少)。在响应xml中的每次更新之后,由于映射的Java类没有所有文件,所以我的代码中断了。 如果响应XML中发生任何更改,是否有任何方法可以避免我的代码中断。 任何帮助将不胜感激。 谢谢。 问题答案: 要处理未知字段,可以添加带注释的属性 输入中与类的显式属性不对应的任何元素都将被扫入此列表。如果该元素是已知的,则将得到未编组
我想使用jaxb解组一个带有这个xsd定义的XML文件。 我已经用eclipse右键生成了java类,生成jaxb类等等。我对解组XML文件没有问题。 问题是我不知道如何取消列表(map?)MetadataType。下面是metadataType的xsd定义和生成的类: 为此类型生成的类是: 外部xsd for在这里 更新: 另外,我从外部 xsd 生成了类: OaiDcType类型。java元素
我得到了一个XML响应,它经常变化(节点不断增加或减少)。在响应xml的每次更新之后,我的代码会中断,因为映射的Java类没有所有的文件。 谢了。
对象使用JAXBContext创建的封送器进行封送。生成的xml将变成: 类Hi是从不能更改的xsd生成的。我的问题是,如果“hello”为null,有没有一种方法可以让封送器忽略nillable参数,并且不向xml输出任何内容?