Как расширить JAXBContext, используемый классами, сгенерированными CXF wsdl2java, чтобы включить дополнительный ObjectFactory

Что?

Я использую wsdl2java CXF для создания классов Java из предоставленного извне wsdl (TravelItineraryReadRQ.wsdl). Когда я вызываю операцию, я получаю ответ, который я могу преобразовать в классы 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 XML, используя JAXBContext, инициализированный следующим образом:

Контекст 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

Аннотация @XmlSeeAlso в сгенерированном wsdl интерфейсе *PortType содержит список классов ObjectFactory. Копируя и расширяя интерфейс TravelItineraryReadPortType и добавляя com.sabre.ns.ticketing.pqs.v1_0.ObjectFactory в список в аннотации @XmlSeeAlso, мне удалось вызвать ошибку проверки XML во время десортировки некоторых дочерних элементов элемента PriceQuoteInfo:

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

Хотя это не очень элегантно, это показывает, что этот подход пытается демаршалировать PriceQuoteInfo, а не оставлять его как объекты DOM, но что XML не совсем соответствует сгенерированной мной схеме GetPriceQuote. Я либо отключу проверку, либо найду подходящую схему, чтобы решить эту проблему.

Вопрос

Можно ли повлиять на JAXBContext, используемый в вызове веб-службы CXF/JAX-WS, чтобы добавить ObjectFactory для PriceQuoteInfo к сгенерированному *PortType?

Например: есть ли способ повлиять на сгенерированную аннотацию @XmlSeeAlso, чтобы она включала этот ObjectFactory, используя внешние привязки?


person roj    schedule 20.02.2019    source источник


Ответы (1)


Была аналогичная проблема. Я не нашел способа повлиять на JAXBContext напрямую, но смог внедрить свою ObjectFactory через JaxWsProxyFactoryBean.setProperties() при создании прокси-сервера JAX-WS:

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

Таким образом, я получил JAXBElement<T> вместо необработанных объектов DOM (в вашем случае T будет PriceQuoteInfo). Надеюсь, это поможет.

person Al3x3    schedule 01.12.2019
comment
У вас синтаксическая ошибка, правильно: factory.setProperties( Collections.singletonMap( jaxb.additionalContextClasses, new Class[]{ObjectFactory.class})); - person Mauricio Zárate; 25.08.2020