Search code examples
javasoapjaxbwsimport

SOAP, JAXB marshalling behavior


I have a WSDL spec, using wsimport to generate client code. (as I've done numerous times before).

Now, one of types in xsd:

<xs:complexType name="Credential">
  <xs:sequence>
    <xs:element minOccurs="0" name="UID" nillable="true" type="xs:string"/>
    <xs:element minOccurs="0" name="UIDBranch" nillable="true" type="xs:string"/>
    <xs:element minOccurs="0" name="PWD" nillable="true" type="xs:string"/>
    <xs:element minOccurs="0" name="Signature" nillable="true" type="xs:string"/>
  </xs:sequence>
</xs:complexType>

And corresponding java binding:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Credential", namespace = "http://schemas.datacontract.org/2004/07/...", propOrder = {
  "uid",
  "uidBranch",
  "pwd",
  "signature"
})
public class Credential {

  @XmlElementRef(name = "UID", namespace = "http://schemas.datacontract.org/2004/07/...", type = JAXBElement.class, required = false)
  protected JAXBElement<String> uid;
  @XmlElementRef(name = "UIDBranch", namespace = "http://schemas.datacontract.org/2004/07/...", type = JAXBElement.class, required = false)
  protected JAXBElement<String> uidBranch;
  @XmlElementRef(name = "PWD", namespace = "http://schemas.datacontract.org/2004/07/...", type = JAXBElement.class, required = false)
  protected JAXBElement<String> pwd;
  @XmlElementRef(name = "Signature", namespace = "http://schemas.datacontract.org/2004/07/...", type = JAXBElement.class, required = false)
  protected JAXBElement<String> signature; 

  ... the rest: getters/setters

When in a request an element of this type happens to look like:

<ns2:Credentials>
   <ns4:string>login</ns4:string>
   <ns4:string>password</ns4:string>
   <ns4:string>signature</ns4:string>
</ns2:Credentials>

But it loses names of elements inside the type, the fragment above should look like this:

<ns2:Credentials>                                                               
  <ns4:UID>login</ns4:UID>                                                             
  <ns4:PWD>password</ns4:PWD>                                                             
  <ns4:Signature>signature</ns4:Signature>
</ns2:Credentials>

Why can it be and how to force client to behave in the correct way?

Update Credentials object is created like this (of is ObjectFactory):

Credential cr = of.createCredential()
cr.setUID(of.createString(login))
cr.setPWD(of.createString(password))
cr.setSignature(of.createString(sign))

Solution

  • You get

    <ns4:string>login</ns4:string>
    

    because you use of.createString(login). Use something like of.createUID(...) if you want ns4:UID.

    The thing is, JAXBElement<String> has a string value (ex. login) but also the name of the element (getValue() and getName() respectively). This name is what gives the XML element its name. The ObjectFactory generated by wsimport/xjc usually contains methods to generate such JAXBElement instances. These createFoo-methods take value as input and wrap them in JAXBElements with the corresponding XML names. So when you use createString, you actually say you want string as element name. String in createString is for element name, not for the value type.

    So your ObjectFactory should also have methods like createUID, createPWD, createSignature etc. Use those methods instead of createString.

    By the way, have you actually tried debugging it? The whole story would be pretty obvious if you've taken a look at the source code of ObjectFactory, any reason to avoid that?