Ugly by default

When working with XML schemas, I often find the generated classes ugly by default. That’s why I always customize the generated classes. Although you’ll find many good tutorials and articles about this on the net, I just wanted to show you the basic customizations I usually apply.

For this example I’ve used a WSDL emitted by a belgian government institution since I had to implement a client for it a few years ago.

It is available at this address : http://www.rsvz-inasti.fgov.be/schemas/WS/Loopbaan.

Be also warned that customization like this is mostly a matter of personal taste !

The hideous XMLGregorianCalendar

I really hate the way Java handles date and time - at least before JDK 8 and JSR-310 - especially the Calendar family. So the first thing I do is to get rid of XMLGregorianCalendar and only use a java.util.Date. By the way, I often use CXF as JAX-WS implementation so I tend to use the facilities given by this framework.

<jaxb:javaType name="java.util.Date"
              xmlType="xs:dateTime"
              parseMethod="org.apache.cxf.xjc.runtime.DataTypeAdapter.parseDateTime"
              printMethod="org.apache.cxf.xjc.runtime.DataTypeAdapter.printDateTime"/>
<jaxb:javaType name="java.util.Date"
              xmlType="xs:date"
              parseMethod="org.apache.cxf.xjc.runtime.DataTypeAdapter.parseDateTime"
              printMethod="org.apache.cxf.xjc.runtime.DataTypeAdapter.printDateTime"/>

You can find the class DataTypeAdapter by adding a tiny dependency in your project :

<dependency>
    <groupId>org.apache.cxf.xjc-utils</groupId>
    <artifactId>cxf-xjc-runtime</artifactId>
    <version>2.6.1</version>
</dependency>

Separate classes

By default, JAXB creates nested classes when it can. This is caused by

<xs:attribute name="localScoping" default= "nested">

from bindingschema_2_0.xsd.

In my example, it produces 75 files.

$ find . -type  f -iname *.java |wc -l
75

I don’t really like nested classes, I prefer separate classes. One can argue in favor of them with the encapsulation argument, for example. That’s true, but I won’t debate this in here. As I said, it’s mostly a matter of aesthetic preferences in this case.

So, let’s change the localScoping attribute of globalBindings element :

<jaxb:globalBindings localScoping="toplevel"/>

After that I get 87 files :

$ find . -type f -iname *.java |wc -l
87

As you can see, the number of classes has slightly raised. There are no nested classes anymore.

Class name customization

Sometimes when creating separate classes it happens some class name clashing : two generated classes have the same name.

I have to admit that I’ve encountered this only once so far; it is clear that the cause is the localScoping attribute set to topLevel.

In order to avoid that, you have to define some XPath expression in order to isolate the XML data type that will be converted to a Java class and assign it a name you’ve defined, like this :

<jaxb:bindings schemaLocation="xml/schema/Loopbaan/B2BExchanges_V1.xsd"
               node="//xs:complexType[@name='Response74LSignalStruct']//xs:element[@name='Activities']/xs:complexType">
        <jaxb:class name="ResponseActivities"/>
</jaxb:bindings>

<jaxb:bindings schemaLocation="xml/schema/Loopbaan/B2BExchanges_V1.xsd"
               node="//xs:complexType[@name='Request74LSignalStruct']//xs:element[@name='Activities']/xs:complexType">
        <jaxb:class name="RequestActivities"/>
</jaxb:bindings>

Here we have two datatypes with the same name, but with different scopes, so they don’t clash in the schema. So if we let localScoping=nested, the generated classes will be nested. No problem then. But here it’s a bit different, JAXB tries to create two classes with the same name (Activities for instance) and fails.

Luckily we instructed JAXB to create two different classes by telling it with a XPath expression.

WSDL customization

Parameter types

As stated before the schemas are imported from a WSDL. When generating classes for the latter we can also do some customization.

For this, you have to use a JAX-WS binding file. I’ll show you a very simple one shortly.

A customization I really always do for SOAP webservices is to disable the wrapper style, enabled by default.

If enabled, it gives you something like this - I’ve removed nearly all annotations for readability :

public void uploadFullCareer(
  @WebParam(mode = WebParam.Mode.INOUT)
  javax.xml.ws.Holder<be.codinsanity.jaxb.inasti.metainfo.ApplHeaderStruct> applHeader,
  be.codinsanity.jaxb.inasti.metainfo.FluxDescriptorStruct fluxDescriptor,
  be.codinsanity.jaxb.inasti.b2bexchanges.UploadCareerDataStruct uploadCareerData
) 

This method has void as return type. So you’re tempted to think that it doesn’t return anything. That’s a bit misleading : the first parameter, which is a Holder holds the response too.

When you look a bit closer, you see the @WebParam(mode = WebParam.Mode.INOUT) annotation. The meaning should be pretty obvious, it just tells that the

As I said it’s misleading, so I prefer the version generated with

<jaxws:enableWrapperStyle>false</jaxws:enableWrapperStyle>

which looks like this :

public UploadFullCareerResponse uploadFullCareer(
    UploadFullCareer parameters
) 

I really prefer the second version. By the way, if someone has technical arguments in favor of the first version, please let me know.

Package name

I like clean packages names, no underscores, least numbers as possible, …

But by default the generated package names are guessed from the XML namespaces where the datatypes live. That’s a sane default after all, but that often leads to horrible package names, like be.fgov.rsvz_inasti.schemas.ws.loopbaan.v1 or org.w3._2001.xmlschema. Huh !

That’s why I use custom name mapping between namespaces and packages. The cxf-codegen-plugin, used from Maven, have an option so you can do this easily :

<plugin>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-codegen-plugin</artifactId>
    <version>${cxf.version}</version>
    <executions>
        <execution>
            <id>generate-sources</id>
            <configuration>
                <defaultOptions>
                    <bindingFiles>
                        <bindingFile>${basedir}/src/main/resources/jaxws-binding.xml</bindingFile>
                    </bindingFiles>
                    <extraargs>
                        <extraarg>-p</extraarg>
                        <extraarg>
                            http://www.rsvz-inasti.fgov.be/schemas/WS/Loopbaan/V1=be.codinsanity.jaxb.inasti.loobpaan
                        </extraarg>
                    </extraargs>
                </defaultOptions>
                <wsdlOptions>
                    <wsdlOption>
                        <wsdl>src/main/resources/xml/Loopbaan/NisseLoopbaan_V1.wsdl</wsdl>
                    </wsdlOption>
                </wsdlOptions>
            </configuration>
            <goals>
                <goal>wsdl2java</goal>
            </goals>
        </execution>
    </executions>
</plugin>

That’s better !

Conclusion

Here I showed you some basic customizations I tend to use everytime I deal with JAXB and JAX-WS.

Of course there many other ways to customize the way classes are generated, either for XML schemas or WSDL’s, that’s why I give you some links hereafter.

I hope it will help you generating more appealing classes.