如何扩展由CXF wsdl2java生成的类使用的JAXBContext,以包括一个附加的ObjectFactory

时间:2019-02-20 03:36:33

标签: xml cxf jax-ws wsdl2java sabre

什么?

我正在使用CXF的wsdl2java从外部提供的wsdl(TravelItineraryReadRQ.wsdl)生成Java类。 当我调用该操作时,我得到一个可以解组为Java类的响应,除了一个元素及其子元素(默认为DOM元素(ElementNSImpl

此元素有何特色?

相关元素(PriceQuote)的类型(PriceQuoteType)在OpenReservation模式中定义为xs:any

<xsd:complexType name="PriceQuoteType">
  <xsd:choice>
      <xsd:any processContents="strict"/>
    </xsd:choice>
</xsd:complexType>

为什么会这样?

我收到的元素(一个PriceQuoteInfo元素属于此wsdl中未引用的名称空间,因此ObjectFactory所创建的JAXBContext类均未使用,可以解组元素。因此,它最终成为原始DOM元素(ElementNSImpl)。

我是否具有定义PriceQuoteInfo类型的架构?

是的,我已经获得了它,并在其上运行wsdl2java为其生成Java类并将它们附加到类路径中。

我尝试了什么?

为了使PriceQuoteInfo能够独立解组,我创建了一个外部绑定文件以将PriceQuoteInfo注释为XmlRootElement,并在maven构建中引用了该文件:

<jaxb:bindings version="2.1"
               xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
               xmlns:xsd="http://www.w3.org/2001/XMLSchema"
               xmlns:annox="http://annox.dev.java.net"
               jaxb:extensionBindingPrefixes="annox">    
    <jaxb:bindings schemaLocation="../PriceQuoteServices_v.3.0.0.xsd" node="/xsd:schema">
       <jaxb:bindings node="xsd:complexType[@name='PriceQuoteInfo.Get.Response']">
            <jaxb:class name="PQSPriceQuoteInfo"/>
            <annox:annotate target="class">
                <annox:annotate annox:class="javax.xml.bind.annotation.XmlRootElement" name="PriceQuoteInfo" namespace="http://www.sabre.com/ns/Ticketing/pqs/1.0"/>
            </annox:annotate>
        </jaxb:bindings>
    </jaxb:bindings>
  </jaxb:bindings>

部分成功

然后,我可以使用初始化为以下内容的PriceQuoteInfo来独立解组JAXBContext XML:

  

JAXBContext上下文= JAXBContext.newInstance(PQSPriceQuoteInfo.class)

在将PriceQuoteInfo作为TravelItineraryReadRS元素的子元素进行解组时,我也可以通过将JAXBContext声明为以下内容来对其进行解组:

  JAXBContext context = JAXBContext.newInstance(TravelItineraryReadRS.class, PQSPriceQuoteInfo.class)

或使用其对象工厂:

  JAXBContext context = JAXBContext.newInstance(com.sabre.services.res.tir.v3_10.ObjectFactory.class, com.sabre.ns.ticketing.pqs.v1_0.ObjectFactory.class)

解组代码是什么样的?

    InputStream inputStream = MyUnitTest.getResourceAsStream(filename)
    Unmarshaller unmarshaller = context.createUnmarshaller()
    JAXBElement<TravelItineraryReadRS> travelItineraryReadRS = unmarshaller.unmarshal(new StreamSource(inputStream), TravelItineraryReadRS.class)

这会将某些TravelItineraryReadRS XML编组为Java类,而没有任何原始DOM对象。

那是什么问题?

当我通过CXF / JAX-WS调用此服务时,PriceQuoteInfo将编组为原始DOM元素,因为我还没有找到修改其用于添加缺少的对象工厂的JAXBContext的方法。

@XmlSeeAlso

wsdl生成的* PortType接口上的@XmlSeeAlso批注包含ObjectFactory类的列表。 通过复制和扩展TravelItineraryReadPortType接口并将com.sabre.ns.ticketing.pqs.v1_0.ObjectFactory添加到@XmlSeeAlso批注中的列表中,我成功在解组PriceQuoteInfo元素的某些子元素期间触发了XML验证错误:

unexpected element (uri:"http://www.sabre.com/ns/Ticketing/pqs/1.0", local:"ValidatingCarrier")

尽管不是很优雅,但它表明此方法试图解组PriceQuoteInfo而不是将其保留为DOM对象,但是XML与我生成的GetPriceQuote模式不完全匹配。我将关闭验证或找到匹配的架构来解决该问题。

问题

是否可以影响CXF / JAX-WS Web服务调用中使用的JAXBContext,以便将ObjectFactory的{​​{1}}添加到生成的* PortType中?

例如:是否有一种方法可以通过使用外部绑定来影响生成的@XmlSeeAlso批注,使其包含此ObjectFactory?

1 个答案:

答案 0 :(得分:1)

有类似的问题。我发现没有直接影响JAXBContext的方法,但是在创建JAX-WS代理时,我可以通过JaxWsProxyFactoryBean.setProperties()注入ObjectFactory:

JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setProperties(
    Collections.singletonMap(
                "jaxb.additionalContextClasses",
                new Class[{com.mypackage.ObjectFactory.class});

这样,我得到了JAXBElement<T>而不是原始DOM对象(在您的情况下,T将是PriceQuoteInfo)。 希望有帮助。