Search code examples
javaxmlsoapjaxbwsdl

JAXB POJO's generated from WDSL seem cumbersome to use


I'm not new to SOAP and turning WSDL's into POJO's. I've managed to connect to the web service and retrieve the data I need.

The problem rests in traversing the object hierarchy that the WSDL created. Most of the variables stored in the generated classes are of the type JAXBElement<NameOfJavaClassHere>. So when ever I want that object I need to issue a call like ListOfEntitiesType loe = ents.getListOfEntities().getValue(); The .getValue() is where I have my issue.

Does there exist a way of making this a smoother integration? If I have to keep doing a getValue() it's going to be a death of 1000 cuts.

It feels like they left in a level of indirection at the client level that they didn't need to.

I've tried to unmarshal the xml with a JAXBContent object, there are a lot of examples on the net on how to do this, but it didn't work in this case. My object came out as null.

Should the WSDL not make POJO's that don't need all this casting about with generics?

Did I use the wrong settings on my wsimport command that came with java 1.7?

Should I use a different wsimport-ish program altogether to generate my POJO's?

If I have to stick with the .getValue() thing, I think I'd much rather make an xpath interface to the raw XML or turn the whole thing into Hashtables and ArrayLists than deal with this.

At least then, I'd have direct access to the info I want.


Solution

  • This XML schema has probably been developed under the influence of some bureaucratic rule. Consider, e.g.

    <xs:element minOccurs="0" name="DUNSNumber" nillable="true" type="xs:string"/>
    

    which results in a field

    protected JAXBElement<String> dunsNumber;
    

    causing the highly circumstantial get and set procedure you have (rightly) complained about. - What does the XML Schema entry mean? It says the element is a string, can be omitted and it must be possible to distinguish between an empty string and an absent string even when the element is present.

    Here is a little experiment:

    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           version="1.0">
    <xs:element name="root" type="RootType"/>
    <xs:complexType name="RootType">
      <xs:sequence>
        <xs:element maxOccurs="unbounded" name="elem"  type="ElemType"/>
      </xs:sequence>
    </xs:complexType>
    <xs:complexType name="ElemType">
      <xs:sequence>
        <xs:element minOccurs="0" name="str01"    type="xs:string"/>
        <xs:element minOccurs="1" name="str1"     type="xs:string"/>
        <!-- The following element compiles to a JAXBElement<String> -->
        <xs:element minOccurs="0" name="str01nil" nillable="true" type="xs:string"/>
        <xs:element minOccurs="1" name="str1nil"  nillable="true" type="xs:string"/>
      </xs:sequence>
    </xs:complexType>
    </xs:schema>
    

    And here is an XML file:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >
      <elem>
        <str01></str01>
        <str1></str1>
        <str01nil></str01nil>
        <str1nil></str1nil>
      </elem>
      <elem>
        <str1>must be there</str1>
        <str01nil xsi:nil="true"></str01nil>
        <str1nil>must be there</str1nil>
      </elem>
    </root>
    

    And here is what is printed by an unmarshalling routine:

    str01    []
    str1     []
    str01Nil []
    str1Nil  []
    str01    [null]
    str1     [must be there]
    str01Nil [null]
    str1Nil  [must be there]
    

    What happens if you omit <str01nil xsi:nil="true"></str01nil> completely? The outcome will be the same, method JAXBElement.getValue() will return null, and that's it.

    Now (sorry for the length of the answer) we can discuss what you can do to return to "sane" Java code generated from the XML schema. I would simply remove nillable="true" and use the resulting code. If you marshal, a null in a field will not produce an element. On unmarshal, there's the weak chance that you see an empty element with an xsi:nil="true". (It is essential to retain minOccurs="0", though.)