Thursday 29 November 2012

Maven & xjc

Maven integration of xjc is available from a number of sources.  In this post I'll look at some examples of what is available from jvnet.

Documentation is available here: http://confluence.highsource.org/display/J2B/JAXB2+Basics+Plugins

Simple Example


    <plugin>
        <groupId>org.jvnet.jaxb2.maven2</groupId>
        <artifactId>maven-jaxb2-plugin</artifactId>
        <executions>
            <execution>    
                <goals>
                    <goal>generate</goal>
                </goals>
            </execution>
        </executions>
        <configuration>
            <extension>true</extension>
           <schemaDirectory>src/main/resources</schemaDirectory>
           <schemaIncludes>
               <include>my_schema.xsd</include>
           </schemaIncludes>
            <generateDirectory>src/main/java</generateDirectory>
            <generatePackage>com.me.generated</generatePackage>
            <episode>false</episode>     
        </configuration>
    </plugin>

This simple example generates my_schema.xsd JAXB classes and puts them into src/main/java in the com.me.generated package.  This is pretty much the most simple example of this plugin.


Example With Catalogue File

    <plugin>
        <groupId>org.jvnet.jaxb2.maven2</groupId>
        <artifactId>maven-jaxb2-plugin</artifactId>
        <version>0.8.2</version>
        <executions>
            <execution>
                <goals>
                    <goal>generate</goal>
                </goals>
            </execution>
        </executions>
        <configuration>
            <extension>true</extension>
            <generateDirectory>src/main/java</generateDirectory>

            <catalogs>
                <catalog>
                    <dependencyResource>            
                        <groupId>com.me.common</groupId>
                        <artifactId>xsd-project</artifactId>
                        <resource>common.catalog</resource>
                    </dependencyResource>
                </catalog>
            </catalogs>

            <episodes>
                <episode>
                    <groupId>com.me.common</groupId>
                    <artifactId>xsd-project</artifactId>
                </episode>
            </episodes>    

            <episode>true</episode> 

            <args>
                <arg>-XtoString</arg>
                <arg>-Xequals</arg>
                <arg>-XhashCode</arg>
            </args>
            <plugins>
                <plugin>
                    <groupId>org.jvnet.jaxb2_commons</groupId>
                    <artifactId>jaxb2-basics</artifactId>
                    <version>0.6.4</version>
                </plugin>
             </plugins>      
        </configuration>    
    </plugin>


This plugin will parse the available *.xsd files in the src/main/resources directory and create JAXB annotated classes in the src/main/java directory.  If an bindings.xjb is also present in the resources directory then this will be used.

generateDirectory - where to put the JAXB classes.
catalogs - These allow an xsd reference to be overridden and redirected locally or into a jar file.
episodes - This tells xjc to not create code for these xsd because it is already available.
episode - This tells xjc to generate an episode file for these xsds
args - optional arguments to add to the JAXB classes.  This requires the plugin that follows it.

Catalog File

A catalog file allows the xsd schema locations to be altered and redirected.  If a schema file has an import such as


    <xs:import namespace="http://www.me.com/common/config" />


Note there is no schemaLocation value.  This will fail the schema validation without a catalog file helping to tell xjc where the actual xsd source is.  A valid catalog file to do this would be

    PUBLIC "http://www.me.com/common/config" "maven:com.me.common:xsd-project!/config.xsd"

Here the first part of the catalog has the same namespace as the import namespace.  This is how they match. The second element can be a standard file location or, like here, a reference to an xsd in a jar which is a maven dependency.  It is only with the maven plugin that this maven:... reference will work.  Standard xjc does not recognise this notation. NOTE: there is a colon separating 'maven' from the groupId from the artifactId.  Putting a . instead will cause the catalogue redirect to not work and that can eat up time trying to find the reason why!!

Episode File

An episode file is just a standard bindings file.  It tells xjc not to create JAXB annotated classes for objects which may appear in an xsd (Not all the elements of the xsd need to be contained in an episode file although this would be a little unusual and require manually changing the episode file after generation).
This maven plugin can use episode files from other jars but can also be told to generate one using the

            <episode>true</episode> 

Common Errors

If you get a stack trace like this,


    com.sun.istack.SAXParseException2: SCD "x-schema::tns" didnt match any schema component

Then a schema is included in the episode file but never referenced.  If you can remove the episode file from the configuration then this will cure it.  Otherwise just create an empty schema which imports all the episode elements but does nothing with them.  I think this error is trying to be helpful and tell you when something is included and it doesn't need to be but the message isn't particularly clear.  Hopefully there may be an option to ignore this error in the future because an episode file may contain multiple schemas when you don't necessarily need them all.


3 comments:

  1. similar issue.. probably was duplicate references

    ReplyDelete
  2. This happened to me when I generated an episode file from a schema that included the "targetNamespace" attribute in the root schema element, but did not include a matching "xmlns:tns" attribute. Apparently the reference in the episode file generated by XJC looks for the tns abbreviation.

    ReplyDelete