I was completing work on a web service using JAX-WS on the server side. In many of the domain objects I used @XmlRootElement
to help facilitate the unmarshaling of XML files into the service using JAXB. All went well and the output was what I expected to see using SoapUI.
However, when I used wsimport to create the client (as a convenience DAO for other developers), I started encountering NullPointerExceptions in my client integration-test class.
The call to the webservice worked correctly, and a response was received by the client, but my more-complex objects were null. Simple attributes, like Strings, were returning full of usable data, but not the larger objects.
Through iterations of recreating services using simple Strings and migrating to more complex objects, I discovered that when the client received objects that were declared on the server with @XmlRootElement
, these were the objects that were null. If the server object did not have the @XmlRootElement
annotation, the client received all of the data in all of its complex glory.
Initially the lack of @XmlRootElement
gave me fits with unmarshaling the data on the server, but this answer helped me out.
So, the phenomenon of the wsimport client silently failing on the unmarshaling of the web service response because of the @XmlRootElement
annotation (on the server!) has me concerned. In this case I had control of both sides and could do something about it. But, what if I don't have control of the server? How would I have resolved this with just the wsimport-generated code?
Found the answer, or the reason, so thought I would share.
The @XmlRootElement
annotation is useful for plain JAXB
bindings, but when the objects (and the resulting XML) are packaged as a SOAP
response it is possible that they don't exactly match the WSDL
's representation of the data depending on the value of other annotations.
With the @XmlRootElement
annotation on the class on the server which is being returned by a @WebMethod
method, the WSDL
will include an element definition such as:
<xs:element name="foo" type="tns:FooType"/>
then elsewhere your WSDL
will include a reference to the element in a sequence such as:
<xs:seqeunce>
<xs:element maxOccurs="unbounded" minOccurs="0" ref="tns:foo"/>
</xs:sequence>
This referencing is caused by the @XmlRootElement
annotation may confuse the intent of the root element declaration compared to the actual XML of the SOAP response.
In contrast, the WSDL
generated without the @XmlRootElement
annotation on the server objects does not contain a <xs:element name="foo"/>
declaration at all. Rather its element is described as:
<xs:sequence>
<xs:element maxOccurs="unbounded" minOccurs="0" name="foo" type="tns:FooType"/>
</xs:sequence>
This probably better matches the way the SOAP response XML is represented and the unmarshalling of the XML into the classes generated by wsimport
works just fine.
How to use @XmlRootElement
in a JAX-WS
service?
wsimport
seems to handle some degree of laziness in the validity of the XML returned by a service. The lesson learned is to be diligent in your use of name
and targetNamespace
on your @WebResult
annotations describing your web service method. The @XmlRootElement
annotation needs to match the name
within the targetNamespace
. When they all match, the unmarshalling happens as expected. When those values do not match, your stubbed classes generated and annotated by wsimport
will not be able to properly consume the XML.
来源:https://stackoverflow.com/questions/14149121/why-does-wsimport-have-trouble-with-server-object-having-xmlrootelement-annotat