Home > Java > Customize your JAXB bindings

Customize your JAXB bindings

JAXB is a bridge between the Java and the XML worlds, enabling your code to transparently marshalls and unmarshalls your Java objects to and from XML. In order to do this, you should have a class representing your XML-Schema. This class is created by the xjc. In most cases, xjc creates a class that won’t suit your needs. In this article, we’ll see why it does so and what we can do to customize this behaviour.

Prerequisite

This article suppose you use a Java Development Kit 6.0. Be wary that different updates of this same JDK 6 use different JAXB versions:

Update JAXB version
3 2.0.3
4 2.1.3

Concurrent technologies

Before diving into JAXB, one should ask oneself whether using JAXB is necessary. There’s a plethora of frameworks whose goal is to serialize/deserialize Java objects to and from XML:

  • Historically speaking (and from my humble knowledge), Castor XML was the first widely used framework to manage Java XML serialization.
  • Since Java 1.4, two classes XMLEncoder and XMLDecoder are available. Their are respectively equivalent to ObjectOutputStream and ObjectInputStream, only they produce XML instead of bytes.
  • Finally, XStream is a 3rd party framework that is fast to run and easy to use.

All these solutions are very good in reading/producing XML, yet they completely ignore the binding part. Binding is the creation of the Java class from the schema. Of course, JAXB has this feature.

XJC

xjc is the executable used to create Java classes from XML schemas. Available syntax are DTD, XML-Schema, RELAX NG, RELAX NG Compact and WSDL. Since I now exclusively use Maven to build my projects, I won’t use xjc directly but I’ll configure the Maven POM to use it. The first thing to do is to add the java.net repository to your POM (or your settings file, but I prefer the former):


    
        maven2-repository.dev.java.net
        Java.net Maven 2 Repository
        http://download.java.net/maven/2
    


    
        maven2-repository.dev.java.net
        Java.net Maven 2 Repository
        http://download.java.net/maven/2
    

Now, you’re ready to use the plugin:


    
        
            org.jvnet.jaxb2.maven2
            maven-jaxb2-plugin
            0.7.1
            ...
        
    

Use the plugin with the following command line: mvn org.jvnet.jaxb2.maven2:maven-jaxb2-plugin:generate.

Common configuration

The previous command line will fail since we didn’t specify any configuration yet. The following should be assumed a good default:


    src/main/resources/schema
    src/main/generated
    false

This tells xjc to look for all xsd files under the src/main/schema directory and generate the classes under src/main/generated. It will use the binding files (*.xjb) under the former directory.

I sincerely advise you to set the removeOldOutput to false since xjc will erase all the directory content. If you use a source code management tool, this will include the directories used by your SCM (.cvs or .svn), a very bad idea.

You need two things still. The first is to set the the compiler level to at least 1.5 in order to annotations to work:


    maven-compiler-plugin
    
        1.6
        1.6
    

Maven only accepts a single source directory. The second thing to do is to make the  src/main/generated directory to Maven when building the project. It can be done with the help of the builder plugin:


    org.codehaus.mojo
    build-helper-maven-plugin
    
        
            add-source
            generate-sources
            
                add-source
            
            
                
                    src/main/generated
                
            
        
    

Now using the previous command line will produce something useful! Try it and you will have some nice surprise.

Customization

In order to customize your bindings, you basically have 2 options:

  • polluting your XML Schema with foreign namespaces,
  • or keeping your XML Schema pure and putting all your bindings into a external file.

From the terms I used, you can guess I prefer option 2. This is the right time to use a binding file. Create a file named binding.xjb under src/main/resources/schema.

Package name

Of  course, the package name is not something desirable: by default, it is the XML-Schema namespace minus http:// plus _package. The first customization is to change this behaviour. Put the following content into your binding file:



    
        
    

If you have the following error, you should use update 14 from JDK 6:

java.lang.LinkageError: JAXB 2.0 API is being loaded from the bootstrap classloader, but this RI (from jar:file:/C:/${user.home}/.m2/repository/com/sun/xml/bind/jaxb-impl/2.1.10/jaxb-impl-2.1.10.jar!/com/sun/xml/bind/v2/model/impl/ModelBuilder.class) needs 2.1 API. Use the endorsed directory mechanism to place jaxb-api.jar in the bootstrap classloader. (See http://java.sun.com/j2se/1.5.0/docs/guide/standards/)

If not, chances are your classes will have been generated under the suitable package name.

Serializable

Managing your entities will probably require you to have them serializable. In order to achieve this, you’ll have to modify your binding file to add the java.io.Serializable interface to your classes along with a serialVersionUID. Every class generated will now be serializable and have the specified uid: a limitation of this process is that each of your generated class will have the same uid.



    
        
    
    
        
     
Superclass

It is sometimes beneficial that all your bound classes inherit from a common class, one that is not described in the XSD. This may happen if this superclass is entirely for technical purpose (sucha as strong typing) and shouldn’t clutter the schema.

In order to do so, two actions are necessary:

  • enable the extended mode for the xjc compiler. Just add true under your configuration in the POM
  • use the superClass tag in the http://java.sun.com/xml/ns/jaxb/xjc namespace

This class won’t be generated by xjc so you are free to create it as you please (making it abstract, adding methods and so on).



    
        
    
    
        
        
    

Data type

By default, xjc will bind the schema to the most precise data type available. For example, a XML-Schema date type will be bound to a Java javax.xml.datatype.XMLGregorianCalendar. This has the drawback of coupling your bound classes to the JAXB API and forcing you to use classes you don’t really need. For purpose of example, check how to convert a java.sql.Date from the database to your entity javax.xml.datatype.XMLGregorianCalendar: have fun!

To ease your development, you can provide both during binding and marshalling/unmarshalling adapters meant to pass to and from XML. This is declared as such in the bindings file:



    
        
            
        
        
            
            
            
        
    

Notice you got another namespace to manage. This will generate an adapter class under the org.w3._2001.xmlschema package you’ll have to use during marshalling/unmarshalling process.

Tweaking the output

Not every information you’ll need in Java will be provided by the XML-Schema. What about compairing our objects with equals()?

Not every schema you’ll use will have been designed by you or your team. Some will be legacy, some will be standards… That doesn’t mean you should suffer for other’s lack of good practice. What if the schema uses uppercase tags? Surely, you want your generated classes to follow Sun coding conventions.

The Sun JAXB team provides plugins to the XJC compiler that resolve the above problems. Have a look at them.

For our example, we choose to add hashCode(), equals() and toString() methods to our generated class. A plugin exists to do just that. You only have to configure this generation in the POM, adding the wanted arguments to the compiler and adding the plugins needed to manage these arguments:


...
    
        -XtoString
        -Xequals
        -XhashCode
    
    
        
            org.jvnet.jaxb2_commons
            jaxb2-basics
            0.5.0
        
     

In this specific case, you’ll have to add two more dependencies (Commons Lang and JAXB Basics runtime) to your POM since the generated classes will depend on them:


...
    
        commons-lang
        commons-lang
        2.4
    
    
        org.jvnet.jaxb2_commons
        jaxb2-basics-runtime
        0.5.0
    

JAXB Persistence Bindings

To go even further and have a single entity able to be marshalled by JAXB and managed by your persistence layer, you can use the HyperJaxb product.

HyperJaxb2 cares about Hibernate managed persistence whereas HyperJaxb3 focuses on JPA managed persistence. The latter seems to be suffering from a lack of documentation, but the objective looks promising.

Conclusion

When reading from and writing to XML, one may be provided with a XML Schema. In this case, it is a good practice to bind the schema to Java. JAXB is the standard solution to achieve this. Yet, in many cases, the generated Java classes will be lacking some features: this shouldn’t be considered the end of the world, since the binding process can be customized to take many parameters into account.

You’ll find the sources for this article here.

To go further:

email
Send to Kindle
  1. al0
    November 18th, 2009 at 15:05 | #1

    “yet they completely ignore the binding par” statement is wrong – Castor can generate classes from schemas (and does it likely better than JAXB does, e.g. it is much easier to persuade Castor to generate reasonable equals() and hashCode(), than do the same for JAXB and access methods for choices by Castor are much more reasonable than by JAXB).

  2. November 18th, 2009 at 19:40 | #2

    Duly noted. I worked with an old version of it that lacked the feature and it is not apparent from the main documentation. Thanks for the rectification.

  3. Eric L.
    December 7th, 2009 at 15:11 | #3

    Just a minor comment, I think in general it is better to clean XML files and here in particular, a little cleansing on binding.xjb would help.
    What I mean, is when doing XML in general use namespace and appropriate namespace definitions, it will helps in configuring properly the binding.
    PS: nice article.

  4. July 27th, 2011 at 16:56 | #4

    Hello Nicolas, I’m just writing to thank you for publishing this post. It has been of great help for me (specially the Superclass section).

    Best regards from Uruguay,
    José

  5. July 27th, 2011 at 19:57 | #5

    You’ré welcome!

  6. Richard
    February 19th, 2012 at 14:56 | #6

    Hi,

    thanks for this article!

    One little thing, you’ll also need to set an execution goal for the plugin in order to generate the thing, like:

    org.jvnet.jaxb2.maven2
    maven-jaxb2-plugin
    0.7.1

    generate

    cheers
    R.

  7. Richard
    February 19th, 2012 at 14:57 | #7

    @Richard
    … and you need a proper XML escaping support for this blog too :D

  8. February 19th, 2012 at 17:31 | #8

    You just need to type HTML entities (< and >)

  9. Lény
    May 21st, 2012 at 14:38 | #9

    hello before : thank you for your tutorial, i have got a small problem : I have several xsd and I have an element “foo” I want this Elements extends one abstract class, without the other element of the scheme extends this class because now I use the tag that do all the elements extend from this abstract class.

    have you got a idea for me please?

    Lény

  10. Lény
    May 23rd, 2012 at 12:24 | #10

    I find well made​​:
    http://confluence.highsource.org/display/J2B/Inheritance+plugin
    http://stackoverflow.com/questions/1271980/generating-a-jaxb-class-that-implements-an-interface

    but the problem is thatb : I include in my wsd different wsd secondary and JaxB no understand. you had an idea for includes the wsd in my main wsd

  11. Mary Ann
    June 25th, 2012 at 20:59 | #11

    I am having a problem where I need to supply namespaces defined by a domain-standard xml. They are in the xsd for my request/response definitions, but the code generated by xjc ignores them and sets the namespace to “” in the @XmlElement definitions.

    Example:

    ….

    How do I enforce taking the prefix bindings and namespaces into the generated code?

    Thanks!
    Mary Ann

  12. Mary Ann
    June 25th, 2012 at 21:02 | #12

    My example didn’t come through… It must have eliminated the input from the xsd file. I’ll try again… Imagine that there are proper tags around these things:

    xsd:element name=”ca:element_name” xmlns:ca=’urn:standard-defined’

    xsd:schema attributeFormDefault=”unqualified” elementFormDefault=”qualified” version=”1.0″ xmlns:xsd=”http://www.w3.org/2001/XMLSchema” xmlns=”urn:standard-defined” xmlns:gml=”http://standard-defined”

  13. June 25th, 2012 at 21:04 | #13

    Well, this article is quiet old by now.

    If you’re using Maven as your build tool, I would suggest you use Codehaus JAXB Maven plugin: the xjc goal has a packageName attribute.

  14. sharad
    September 19th, 2012 at 06:50 | #14

    Excellent article. I used bindings effectively after reading your article.

  15. amjed
    January 25th, 2013 at 12:37 | #15

    THanks, this was very helpful.

  1. No trackbacks yet.