在JAXB中,在解组过程中忽略未定义的元素引用

huangapple go评论98阅读模式
英文:

Ignoring undefined element references during unmarshalling in JAXB

问题

我目前正在使用CXF框架开发一个请求Web服务的项目。

由于某些原因,我开始收到无效的XML SOAP(缺少从中引用的ID的元素)响应,导致在将其解组为POJO实例的过程中引发异常。

示例:

XML摘录,其中属性ref引用了XML中不存在的标识符为Person1的元素。

  1. <ext:Applicant s:ref="Person1"/>

其中ref在XSD架构中的类型为IDREF

  1. <attribute name="ref" type="IDREF"/>

JAXB引发的异常:

  1. javax.xml.ws.soap.SOAPFaultException: 解组错误:未定义的IDPerson1”。带有根本原因的]
  2. javax.xml.bind.UnmarshalException: 未定义的IDPerson1”。
  3. at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:744)
  4. at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.errorUnresolvedIDREF(UnmarshallingContext.java:795)
  5. at com.sun.xml.bind.v2.runtime.reflect.TransducedAccessor$IDREFTransducedAccessorImpl$1.run(TransducedAccessor.java:330)
  6. ...

是否有办法让JAXB忽略缺少的引用,在解组传入的XML响应时不抛出异常?

英文:

I'm currently working on a project requesting web services using CXF framework.

For some reasons, I started to receive invalid XML SOAP(missing element with ID referenced from ) response that results in throwing exception during unmarshalling to POJO instance.

Example:

XML excerpt where attribute ref references to an element with identifier Person1 that does not exist in XML.

  1. <ext:Applicant s:ref="Person1"/>

where ref is IDREF type in XSD schema

  1. <attribute name="ref" type="IDREF"/>

Exception thrown by JAXB

  1. javax.xml.ws.soap.SOAPFaultException: Unmarshalling Error: Undefined ID "Person1". ] with root cause
  2. javax.xml.bind.UnmarshalException: Undefined ID "Person1".
  3. at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:744) ~[jaxb-impl-2.3.1.jar!/:2.3.1]
  4. at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.errorUnresolvedIDREF(UnmarshallingContext.java:795) ~[jaxb-impl-2.3.1.jar!/:2.3.1]
  5. at com.sun.xml.bind.v2.runtime.reflect.TransducedAccessor$IDREFTransducedAccessorImpl$1.run(TransducedAccessor.java:330) ~[jaxb-impl-2.3.1.jar!/:2.3.1]
  6. at...

Is there a way how to make JAXB ignore missing references and unmarshall incoming XML response without throwing exception?

答案1

得分: 1

以下是翻译好的部分:

XML对象未在请求中提供,以更具体地讨论。有一个方便的解决方法,可以为JAX-B对象创建CustomAdapter,以确定如何对对象进行marshalunmarshal

例如,可以实现如下所示的CustomAdapter

  1. public static class CustomAdapter extends XmlAdapter<Object, Person1> {
  2. @Override
  3. public Object marshal(Person1 value) {
  4. // 您的编组实现
  5. }
  6. @Override
  7. public Person1 unmarshal(Object value) {
  8. // 您的解组实现
  9. }
  10. }

XmlAdapter位于javax.xml.bind.annotation.adapters.XmlAdapter包中。

如果您将Person1用作其他对象(组合)中的字段,则可以像下面这样用@XmlJavaTypeAdapter进行注释:

  1. @XmlJavaTypeAdapter(CustomAdapter.class)
  2. private Person1 person1;

如果有帮助,请告诉我。

英文:

The XML object is not provided in the request to discuss more specifically. There is a handy workaround to create CustomAdapter for JAX-B objects to determine how to marshal and unmarshal the object.

As an example, the below CustomAdapter could be implemeted:

  1. public static class CustomAdapter extends XmlAdapter&lt;Object, Person1&gt; {
  2. @Override
  3. public Object marshal(Person1 value) {
  4. // your implementation to marshal
  5. }
  6. @Override
  7. public Person1 unmarshal(Object value) {
  8. // your implementation to unmarshal
  9. }
  10. }

XmlAdapter is in javax.xml.bind.annotation.adapters.XmlAdapter package.

If you are using Person1 as a field in other objects (composition), you could make it annotated with @XmlJavaTypeAdapter as below:

  1. @XmlJavaTypeAdapter(CustomAdapter.class)
  2. private Person1 person1;

Please let me know if it helps out.

答案2

得分: 0

可能的解决方案可以是为XMLEventReader创建一个装饰器,用于过滤掉IDREF属性(或其他必要的属性):

  1. public class IdRefFilteringReader implements XMLEventReader {
  2. /**
  3. * 需要移除的属性的QName
  4. */
  5. private final static QName QNAME = new QName("http://www.w3.org/2001/XMLSchema", "ref");
  6. /**
  7. * 委托的XML事件阅读器
  8. */
  9. private final XMLEventReader delegate;
  10. /**
  11. * XML事件工厂
  12. */
  13. private final XMLEventFactory eventFactory = XMLEventFactory.newInstance();
  14. /**
  15. * 构造函数注入委托
  16. */
  17. public IdRefFilteringReader(XMLEventReader delegate) {
  18. this.delegate = delegate;
  19. }
  20. /**
  21. * 移除具有匹配QName的属性
  22. */
  23. @Override
  24. public XMLEvent nextEvent() throws XMLStreamException {
  25. XMLEvent event = delegate.nextEvent();
  26. if (event.isStartElement()) {
  27. StartElement startElement = event.asStartElement();
  28. Attribute attr = startElement.getAttributeByName(QNAME);
  29. // 如果属性存在,创建一个新的XMLEvent,其前缀、命名空间、名称以及其他属性都相同,
  30. // 唯独要移除一个属性
  31. if(attr != null) {
  32. String prefix = startElement.getName().getPrefix();
  33. String uri = startElement.getName().getNamespaceURI();
  34. String localname = startElement.getName().getLocalPart();
  35. List<Attribute> attributes = new ArrayList<>();
  36. startElement.getAttributes().forEachRemaining(a -> {
  37. if(!a.getName().equals(attr.getName())) {
  38. attributes.add(a);
  39. }
  40. });
  41. return eventFactory.createStartElement(
  42. prefix,
  43. uri,
  44. localname,
  45. attributes.iterator(),
  46. startElement.getNamespaces()
  47. );
  48. }
  49. }
  50. return event;
  51. }
  52. @Override
  53. public boolean hasNext() {
  54. return delegate.hasNext();
  55. }
  56. @Override
  57. public XMLEvent peek() throws XMLStreamException {
  58. return delegate.peek();
  59. }
  60. @Override
  61. public String getElementText() throws XMLStreamException {
  62. return delegate.getElementText();
  63. }
  64. @Override
  65. public XMLEvent nextTag() throws XMLStreamException {
  66. return delegate.nextTag();
  67. }
  68. @Override
  69. public Object getProperty(String name) throws IllegalArgumentException {
  70. return delegate.getProperty(name);
  71. }
  72. @Override
  73. public void close() throws XMLStreamException {
  74. delegate.close();
  75. }
  76. @Override
  77. public Object next() {
  78. return delegate.next();
  79. }
  80. }

要使用这个阅读器,需要将其传递给unmarshaller实例,例如:

  1. // 创建unmarshaller
  2. JAXBContext ctx = JAXBContext.newInstance(Applicant.class);
  3. Unmarshaller unmarshaller = ctx.createUnmarshaller();
  4. // 创建常规的XML事件阅读器和经过过滤的XML事件阅读器
  5. XMLInputFactory xif = XMLInputFactory.newInstance();
  6. XMLEventReader reader = xif.createXMLEventReader(new StreamSource(new StringReader(xml)));
  7. XMLEventReader filteringReader = new IdRefFilteringReader(reader);
  8. // 使用过滤的阅读器进行XML解组
  9. Applicant applicant = unmarshaller.unmarshal(filteringReader, Applicant.class);
英文:

Possible solution could be creating a decorator for XMLEventReader, which will filter out the IDREF attributes (or other attributes if needed):

  1. public class IdRefFilteringReader implements XMLEventReader {
  2. /**
  3. * QName of the attribute to be removed
  4. */
  5. private final static QName QNAME = new QName(&quot;http://www.w3.org/2001/XMLSchema&quot;, &quot;ref&quot;);
  6. /**
  7. * Delegate XML event reader
  8. */
  9. private final XMLEventReader delegate;
  10. /**
  11. * XML event factory
  12. */
  13. private final XMLEventFactory eventFactory = XMLEventFactory.newInstance();
  14. /**
  15. * Constructor injects delegate
  16. */
  17. public IdRefFilteringReader(XMLEventReader delegate) {
  18. this.delegate = delegate;
  19. }
  20. /**
  21. * Remove attributes with matching QName
  22. */
  23. @Override
  24. public XMLEvent nextEvent() throws XMLStreamException {
  25. XMLEvent event = delegate.nextEvent();
  26. if (event.isStartElement()) {
  27. StartElement startElement = event.asStartElement();
  28. Attribute attr = startElement.getAttributeByName(QNAME);
  29. // if attribute is present, create new XMLEvent with same
  30. // prefix, namespace, name and other attributes except one
  31. // which should be removed
  32. if(attr != null) {
  33. String prefix = startElement.getName().getPrefix();
  34. String uri = startElement.getName().getNamespaceURI();
  35. String localname = startElement.getName().getLocalPart();
  36. List&lt;Attribute&gt; attributes = new ArrayList&lt;&gt;();
  37. startElement.getAttributes().forEachRemaining(a -&gt; {
  38. if(!a.getName().equals(attr.getName())) {
  39. attributes.add(a);
  40. }
  41. });
  42. return eventFactory.createStartElement(
  43. prefix,
  44. uri,
  45. localname,
  46. attributes.iterator(),
  47. startElement.getNamespaces()
  48. );
  49. }
  50. }
  51. return event;
  52. }
  53. @Override
  54. public boolean hasNext() {
  55. return delegate.hasNext();
  56. }
  57. @Override
  58. public XMLEvent peek() throws XMLStreamException {
  59. return delegate.peek();
  60. }
  61. @Override
  62. public String getElementText() throws XMLStreamException {
  63. return delegate.getElementText();
  64. }
  65. @Override
  66. public XMLEvent nextTag() throws XMLStreamException {
  67. return delegate.nextTag();
  68. }
  69. @Override
  70. public Object getProperty(String name) throws IllegalArgumentException {
  71. return delegate.getProperty(name);
  72. }
  73. @Override
  74. public void close() throws XMLStreamException {
  75. delegate.close();
  76. }
  77. @Override
  78. public Object next() {
  79. return delegate.next();
  80. }
  81. }

To use this reader it's needed to pass it to unmarshaller instance, e.g.:

  1. // create unmarshaller
  2. JAXBContext ctx = JAXBContext.newInstance(Applicant.class);
  3. Unmarshaller unmarshaller = ctx.createUnmarshaller();
  4. // create regular XML event reader and filtered XML event reader
  5. XMLInputFactory xif = XMLInputFactory.newInstance();
  6. XMLEventReader reader = xif.createXMLEventReader(new StreamSource(new StringReader(xml)));
  7. XMLEventReader filteringReader = new IdRefFilteringReader(reader);
  8. // unmarshall XML using filtering reader
  9. Applicant applicant = unmarshaller.unmarshal(filteringReader, Applicant.class);

huangapple
  • 本文由 发表于 2020年10月2日 23:03:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/64173852.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定