h1ghlevelb1ts

JAXB with Maven

Fredrik was recently blogging about "Two way SSL with Java" and about his frustration about the lack of knowledge and documentation. This time I want to blog about another area of software development where frustration is running high - XML processing. On the surface things looks easy, but who does not remember the classpath problems around XML parsing in the early days (SAX vs XERCES vs DOM, etc). And who really fully understands the XSD syntax and is able to create a properly designed xsd? And documentation - let's just not talk about it!

But let's get to the actual problem. I wanted to use JAXB to write a parser for XML files matching a given xsd. Given that Sun introduced JAXB as official XML binding framework for Java it seems the obvious choice for the task. Unfortunately, another requirement was that the code would work under JDK 5 and 6. However, the JAXB API is only offical part of the JDK since version 6. To solve this problem a little trick is needed. Let's take it step by step using Maven as build system. First we have to include the plugin by adding the following to the POM:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>jaxb2-maven-plugin</artifactId>
    <executions>
        <execution>
            <goals>
                <goal>xjc</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <packageName>org.hibernate.validation.xml</packageName>
        <outputDirectory>${basedir}/target/generated-sources</outputDirectory>
        <extension>true</extension>
    </configuration>
</plugin>

The task of the plugin is to create the Java binding classes for the xsd. Per default the xsd file has to be placed into the directory /src/main/xsd. The configuration in the POM specifies the default package name for the generated classes and in which directory the classes have to be generated. The meaning of extension we will discuss a little later.

The setup so far will work fine with JDK 6, but in order to make it work for JDK 5 as well we have to use profiles. The idea is to add the required libraries which are missing in JDK 5 depending on the JDK version. This can be achieved by adding the following to the POM:

<profiles>
        <profile>
            <id>jaxb</id>
            <activation>
                <jdk>1.5</jdk>
            </activation>
            <dependencies>
                <dependency>
                    <groupId>javax.xml.bind</groupId>
                    <artifactId>jaxb-api</artifactId>
                    <version>2.1</version>
                </dependency>
                <dependency>
                    <groupId>com.sun.xml.bind</groupId>
                    <artifactId>jaxb-impl</artifactId>
                    <version>2.1.3</version>
                </dependency>
            </dependencies>
        </profile>
</profiles>

So far things were quite simple to figure out. The hard part is one more requirement I haven't mentioned yet. The parser should be tolerant against whitespaces. Some googling and I figured out that in JAXB this kind of things are done with adapters. In fact the CollapsedStringAdapter seems to be exactly what I want. The javadoc says:"This adapter removes leading and trailing whitespaces, then truncate any sequnce of tab, CR, LF, and SP by a single whitespace character '". Great, but how do I configure JAXB so that it automatically uses this adapter. Here the frustration really starts. The best a search for CollapsedStringAdapter results in is the javadoc for this class. Nothing about how to use it. Not in plain JAXB nor in conjunction with the maven plugin. Frustration started to mount again. To cut a long story short. It took many mailing list posts and a lot of try and error to figure it out. The outcome is that first of all you need the true bit in the plugin configuration. Next you have to create a file called binding-customization.xjb in src/main/xjb. The file has to contain the following:

<?xml version="1.0" encoding="UTF-8"?>
<jxb:bindings version="1.0" xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc">
    <jxb:bindings schemaLocation="../xsd/validation-mapping-1.0.xsd" node="/xs:schema">
        <jxb:globalBindings>
            <xjc:javaType name="java.lang.String" xmlType="xs:string"
                adapter="javax.xml.bind.annotation.adapters.CollapsedStringAdapter"/>
        </jxb:globalBindings>
    </jxb:bindings>
</jxb:bindings>

In the customization file a global binding gets defined for all java.lang.String types. It looks simple, but believe me it was damn hard to figure out. Hopefully this blog will save someone the painful hours I had.


My personal conclusion was that documetnation around XML related topics still sucks :(

--Hardy

Old comments

2009-08-17Fredrik Rubensson
Entirely according to my experience. JAXB sucks when it comes to doing the anything that is outside the simplest thing. It works fine for (un)marshalling but as soon as you want to do something else it is a misery.
2012-12-03lifestyle v35
Hi there, after reading this remaгkable paragraph i am too hapρу to shaгe mу know-how here with collеagues.
2012-12-25cipto junaedy
Hi, аlωays i usеd tο chеck wеb site poѕts here eаrlу in thе daylіght, for the reаson that i liκe tο find out more and more.
2013-02-11PekMypeCheese
Reported in Full-Text Format at: 1997 U.S. App. LEXIS 11418. bankruptcy maryland bankruptcy help orlando florida discount bankruptcy florida