Pages

15 September, 2011

Configure Maven to generate classes from XML Schema using JAXB

In my previous post I showed how to create RESTful services using Spring Framework. For representation of resources in XML I used JAXB and I followed the bottom-up approach (I wrote the Java classes and I let to generate XML/XSD from Java classes). In this post I will demonstrate how you can generate the same Java classes (User and UserList) from XML Schema (XSD) during Maven build, therefore using a top-down approach. For generation of Java classes from XML Schema during Maven build I will use Java.net Maven 2 JAXB 2 Plugin.

Along with the default generation of Java classes from XML Schema using xjc tool, I will add the following customizations:

  • Making all the generated classes to implement Serializable (useful when you want to use classes with some remote services: RMI, EJB, etc).
  • Use java.util.Calendar instead of javax.xml.datatype.XMLGregorianCalendar for fields generated from elements of type xs:dateTime.
  • Generated classes should also have a generated toString() method.
  • Classes have to be annotated with XmlRootElement (required by Spring Framework when classes are used to represent state in RESTful services).
  • You can further enhance and customize the generation of Java classes using various plugins.

Project sources are available for download. So let’s start, step by step:

  1. Create Maven project. Below you can see the POM:
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>org.zmeu</groupId>
        <artifactId>zmeu-blog-maven-jaxb</artifactId>
        <version>1.0-SNAPSHOT</version>
        <name>ZMEU Blog Maven JAXB</name>
        <build>
            <plugins>
                <plugin>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>1.6</source>
                        <target>1.6</target>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.jvnet.jaxb2.maven2</groupId>
                    <artifactId>maven-jaxb2-plugin</artifactId>
                    <version>0.8.0</version>
                    <configuration>
                        <schemaDirectory>src/main/resources/schema</schemaDirectory>
                        <bindingDirectory>src/main/resources/schema</bindingDirectory>
                        <generatePackage>org.zmeu.blog.jaxb</generatePackage>
                        <strict>false</strict>
                        <extension>true</extension>
                        <plugins>
                            <plugin>
                                <groupId>org.jvnet.jaxb2_commons</groupId>
                                <artifactId>jaxb2-basics</artifactId>
                                <version>0.6.2</version>
                            </plugin>
                            <plugin>
                                <groupId>org.jvnet.jaxb2_commons</groupId>
                                <artifactId>jaxb2-basics-annotate</artifactId>
                                <version>0.6.2</version>
                            </plugin>
                        </plugins>
                        <args>
                            <arg>-Xannotate</arg>
                            <arg>-XtoString</arg>
                        </args>
                    </configuration>
                    <executions>
                        <execution>
                            <id>generate</id>
                            <goals>
                                <goal>generate</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
        <dependencies>
            <dependency>
                <groupId>org.jvnet.jaxb2_commons</groupId>
                <artifactId>jaxb2-basics-runtime</artifactId>
                <version>0.6.2</version>
            </dependency>
        </dependencies>
    </project>
    
  2. Write XML Schema (schema.xsd):
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    
        <xs:element name="user" type="user" />
        <xs:element name="userList" type="userList" />
    
        <xs:complexType name="user">
            <xs:all>
                <xs:element name="id" type="xs:long" minOccurs="0" />
                <xs:element name="name" type="xs:string" />
                <xs:element name="registrationDate" type="xs:dateTime" />
            </xs:all>
        </xs:complexType>
    
        <xs:complexType name="userList">
            <xs:sequence>
                <xs:element name="user" type="user" minOccurs="0" maxOccurs="unbounded" />
            </xs:sequence>
        </xs:complexType>
        
    </xs:schema>
    
  3. Customize JAXB Bindings (binding.xjb):
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <jaxb:bindings xmlns:jaxb="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" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:annox="http://annox.dev.java.net" 
        xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd"
        version="2.1">
        <jaxb:globalBindings>
            <!-- Use java.util.Calendar instead of javax.xml.datatype.XMLGregorianCalendar for xs:dateTime -->
            <jaxb:javaType name="java.util.Calendar" xmlType="xs:dateTime"
                    parseMethod="javax.xml.bind.DatatypeConverter.parseDateTime" 
                    printMethod="javax.xml.bind.DatatypeConverter.printDateTime" />
    
            <!-- Force all classes implements Serializable -->
            <xjc:serializable uid="1" />
        </jaxb:globalBindings>
    
        <!-- Annotate the following classes with XmlRootElement -->
        <jaxb:bindings schemaLocation="schema.xsd" node="/xs:schema">
            <jaxb:bindings node="xs:complexType[@name='user']">
                <annox:annotate>
                    <annox:annotate annox:class="javax.xml.bind.annotation.XmlRootElement" name="user" />
                </annox:annotate>
            </jaxb:bindings>
            <jaxb:bindings node="xs:complexType[@name='userList']">
                <annox:annotate>
                    <annox:annotate annox:class="javax.xml.bind.annotation.XmlRootElement" name="userList" />
                </annox:annotate>
            </jaxb:bindings>
        </jaxb:bindings>
    </jaxb:bindings>
    
  4. Run the build using mvn clean install command. Build must be successful. Generated classes will be located in target/generated-sources/xjc directory. Below is a snippet from generated User class:
    
    .....
    
    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "user", propOrder = {})
    @XmlRootElement(name = "user")
    public class User implements Serializable, ToString {
        private final static long serialVersionUID = 1L;
        
        protected Long id;
        
        @XmlElement(required = true)
        protected String name;
        
        @XmlElement(required = true, type = String.class)
        @XmlJavaTypeAdapter(Adapter1 .class)
        @XmlSchemaType(name = "dateTime")
        protected Calendar registrationDate;
    
        .....
    
    }
    
  5. You are done!

0 comments:

Post a Comment