What?
I am using CXF's wsdl2java to generate Java classes from an externally supplied wsdl (TravelItineraryReadRQ.wsdl
).
When I call the operation, I get a response that I can unmarshal into Java classes, with the exception of one element and its children which default to DOM elements (ElementNSImpl
)
What's special about this element?
The element in question (PriceQuote
) is of type (PriceQuoteType
) defined in the OpenReservation schema as xs:any
:
<xsd:complexType name="PriceQuoteType">
<xsd:choice>
<xsd:any processContents="strict"/>
</xsd:choice>
</xsd:complexType>
Why does this happen?
The element that I receive (a PriceQuoteInfo
element) belongs to a namespace that is not referenced in this wsdl, so none of the ObjectFactory
classes that the JAXBContext
has been created with, can unmarshal the element. It therefore ends up as raw DOM elements (ElementNSImpl
).
Do I have the schema where the PriceQuoteInfo
type is defined?
Yes, I have obtained this, and run wsdl2java
on it to generate Java classes for it and appended them to the classpath.
What have I tried?
To enable the PriceQuoteInfo
to be unmarshalled independently, I created an external binding file to annotate the PriceQuoteInfo
as an XmlRootElement
and referenced this file in the maven build:
<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>
Partial Success
I'm then able to unmarshal PriceQuoteInfo
XML independently, using a JAXBContext
initialised as the following:
JAXBContext context = JAXBContext.newInstance(PQSPriceQuoteInfo.class)
When unmarshalling PriceQuoteInfo
as a child of a TravelItineraryReadRS
element, I can also unmarshal it by declaring the JAXBContext
as:
JAXBContext context = JAXBContext.newInstance(TravelItineraryReadRS.class, PQSPriceQuoteInfo.class)
or alternatively, by using their object factories:
JAXBContext context = JAXBContext.newInstance(com.sabre.services.res.tir.v3_10.ObjectFactory.class, com.sabre.ns.ticketing.pqs.v1_0.ObjectFactory.class)
And what does the unmarshalling code look like?
InputStream inputStream = MyUnitTest.getResourceAsStream(filename)
Unmarshaller unmarshaller = context.createUnmarshaller()
JAXBElement<TravelItineraryReadRS> travelItineraryReadRS = unmarshaller.unmarshal(new StreamSource(inputStream), TravelItineraryReadRS.class)
And this unmarshals some TravelItineraryReadRS
XML into Java classes, without any raw DOM objects.
So what's the problem?
When I call this service via CXF / JAX-WS the PriceQuoteInfo
unmarshals into raw DOM elements as I haven't found a way of modifying the JAXBContext
that it uses to add the missing object factory.
@XmlSeeAlso
The @XmlSeeAlso
annotation on the wsdl's generated *PortType interface contains a list of ObjectFactory
classes.
By replicating and extending the TravelItineraryReadPortType
interface and adding com.sabre.ns.ticketing.pqs.v1_0.ObjectFactory
to the list in the @XmlSeeAlso
annotation, I succeeded in triggering an XML validation error during unmarshalling of some children of the PriceQuoteInfo element:
unexpected element (uri:"http://www.sabre.com/ns/Ticketing/pqs/1.0", local:"ValidatingCarrier")
Although not very elegant it shows that this approach is attempting to unmarshal the PriceQuoteInfo
rather than leaving it as DOM objects, but that the XML isn't exactly matching the GetPriceQuote
schema I generated. I'll either turn off validation or find a matching schema to resolve that.
The Question
Is it possible to influence the JAXBContext
used in a CXF / JAX-WS web service call so as to add the ObjectFactory
for PriceQuoteInfo
to the generated *PortType?
For example: is there a way of influencing the generated @XmlSeeAlso annotation so that it includes this ObjectFactory, by using external bindings?