Что?
Я использую 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, используя внешние привязки?