| 10 April 2009 |
I have blogged before about how to generate JAXB binding classes based on your WSDL file, this time I wanted to generate JAXB classes based on just XSD files. Although I expected this to be simple, it took me quite some time to get it right, so I decided to give this item its own post :-)
I have got the following schema 'customer.xsd' that I want to bind to Java classes:
-
<?xml version="1.0" encoding="UTF-8"?>
-
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
-
targetNamespace="http://www.pascalalma.net/schema/customer"
-
xmlns:tns="http://www.pascalalma.net/schema/customer"
-
elementFormDefault="qualified">
-
-
<xsd:element name="customer">
-
<xsd:complexType>
-
<xsd:sequence>
-
<xsd:element name="id" type="tns:idType" />
-
<xsd:element name="name" type="tns:nameType" />
-
<xsd:element name="address" type="tns:addressType" />
-
</xsd:sequence>
-
</xsd:complexType>
-
</xsd:element>
-
<xsd:simpleType name="idType">
-
<xsd:restriction base="xsd:positiveInteger">
-
<xsd:minInclusive value="1"/>
-
<xsd:maxInclusive value="9999999999"/>
-
</xsd:restriction>
-
</xsd:simpleType>
-
<xsd:simpleType name="nameType">
-
<xsd:restriction base="xsd:string">
-
<xsd:minLength value="1"/>
-
<xsd:maxLength value="128"/>
-
</xsd:restriction>
-
</xsd:simpleType>
-
<xsd:simpleType name="addressType">
-
<xsd:restriction base="xsd:string">
-
<xsd:minLength value="1"/>
-
<xsd:maxLength value="255"/>
-
</xsd:restriction>
-
</xsd:simpleType>
-
</xsd:schema>
I have added this schema to my /main/resources/ directory in my Maven project. The generated JAXB objects will be used in an EJB class called 'CustomerLogger'. The class looks like:
-
package net.pascalalma.services;
-
-
import javax.ejb.Stateless;
-
import net.pascalalma.schema.customer.Customer;
-
-
/**
-
*
-
* @author pascal
-
*/
-
@Stateless
-
public class CustomerLogger implements CustomerLoggerRemote {
-
-
public void log(Customer cust)
-
{
-
-
-
}
-
}
and the corresponding interface:
-
package net.pascalalma.services;
-
-
import javax.ejb.Remote;
-
import net.pascalalma.schema.customer.Customer;
-
-
/**
-
*
-
* @author pascal
-
*/
-
public interface CustomerLoggerRemote {
-
-
void log(Customer cust);
-
}
I also created a test class that tests the JAXB marshalling and unmarshallig (only for this case, I don't think you normally want to test that) and the CustommerLogger EJB class. It looks like this:
-
package net.pascalalma.services;
-
-
import java.io.StringReader;
-
import java.io.StringWriter;
-
import java.io.Writer;
-
import javax.xml.bind.JAXBContext;
-
import javax.xml.bind.JAXBElement;
-
import javax.xml.bind.JAXBException;
-
import javax.xml.bind.Marshaller;
-
import javax.xml.bind.Unmarshaller;
-
import javax.xml.transform.Source;
-
import javax.xml.transform.stream.StreamSource;
-
import net.pascalalma.schema.customer.Customer;
-
-
import net.pascalalma.schema.customer.ObjectFactory;
-
import org.junit.After;
-
import org.junit.Before;
-
import org.junit.Test;
-
-
/**
-
*
-
* @author pascal
-
*/
-
public class CustomerLoggerTest extends EJBTestBase {
-
-
private CustomerLoggerRemote cl = null;
-
-
@Before
-
cl = (CustomerLoggerRemote) context.lookup("CustomerLoggerRemote");
-
}
-
-
@After
-
public void tearDownTest()
-
cl = null;
-
}
-
-
@Test
-
-
cl.log(getTestCustomerObject());
-
-
}
-
-
@Test
-
public void unmarshalTest() throws JAXBException {
-
JAXBContext jaxbContext = JAXBContext.newInstance(Customer.class);
-
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
-
-
-
JAXBElement<customer> root = unmarshaller.unmarshal(ss, Customer.class);
-
-
Customer c1 = root.getValue();
-
-
assert c1 != null;
-
assert c1.getId() == getTestCustomerObject().getId();
-
assert c1.getName().equals(getTestCustomerObject().getName());
-
assert c1.getAddress().equals(getTestCustomerObject().getAddress());
-
}
-
-
@Test
-
public void marshallTest() throws JAXBException {
-
JAXBContext jaxbContext = JAXBContext.newInstance(Customer.class);
-
Marshaller m = jaxbContext.createMarshaller();
-
-
-
-
m.marshal(getTestCustomerObject(), sw);
-
-
-
assert result.length()> 0;
-
assert result.indexOf("Palma IT")> 0;
-
assert result.indexOf("Papendrecht")> 0;
-
}
-
return "<customer xmlns=\"http://www.pascalalma.net/schema/customer\">\n" +
-
"\t<id>1</id>\n" +
-
"\t<name>Palma IT</name>\n" +
-
"\t<address>Papendrecht, Holland</address>\n" +
-
"</customer>\n";
-
}
-
-
private Customer getTestCustomerObject() {
-
-
Customer ct = of.createCustomer();
-
ct.setId(1);
-
ct.setAddress("Papendrecht, Holland");
-
ct.setName("Palma IT");
-
-
return ct;
-
}
-
}
Next is setting up the correct plugin in your pom like this:
-
<plugin>
-
<groupId>org.jvnet.jaxb2.maven2</groupId>
-
<artifactId>maven-jaxb2-plugin</artifactId>
-
<executions>
-
<execution>
-
<goals>
-
<goal>generate</goal>
-
</goals>
-
</execution>
-
</executions>
-
<configuration>
-
<schemaDirectory>src/main/resources/schemas</schemaDirectory>
-
<readOnly>true</readOnly>
-
<removeOldOutput>true</removeOldOutput>
-
<verbose>false</verbose>
-
<extension>true</extension>
-
<bindingIncludes>
-
<bindingInclude>jaxb-bindings.xml</bindingInclude>
-
</bindingIncludes>
-
</configuration>
-
</plugin>
As you can see I am reffering to a specific binding file to be used: 'jaxb-bindings.xml'. This file is used to make the generated objects 'serializable' (I described similar situation here). The complete pom can be found here.
If all this is in place you can test your setup by performing
mvn clean install.
Here is my complete project structure:

While putting up this project I ran into several issues:
- First make sure you have the right plugin
- Second please note the differences in including JAXB binding file
- Last issue had to do with my xsd syntax
-
...
-
<xsd:element name="customer" type="tns:customerType" />
-
<xsd:complexType name="customerType">
-
<xsd:sequence>
-
<xsd:element name="id" type="tns:idType" />
-
<xsd:element name="name" type="tns:nameType" />
-
<xsd:element name="address" type="tns:addressType" />
-
</xsd:sequence>
-
</xsd:complexType>
-
...
You should be using this one for JAXB2 and not this one which is for JAXB.
As I set before I did the same thing before using JAXWS plugin, but the syntax of including the binding file and the content of the binding file is a little different in this case, so make sure you are aware of that. I wasn't and it took some time to figure it all out.
Originally I had the following syntax in my XSD file:
But that caused the following exception:
com.sun.istack.SAXException2: unable to marshal type "net.pascalalma.schema.customer.CustomerType" as an element because it is missing an @XmlRootElement annotation
The cause for this issue is described here and it made me to redefine my xsd in the one I showed at top of this post.


2 comments to 'Generating JAXB2 with Maven2'
21 April 2009
[...] Generating JAXB2 with Maven2 [...]
18 November 2009
[...] In my situation I have my JAXB classes generated in the package 'net.pascalalma.types' (I take this post as an example for my JAXB module). The first step is to create a Maven project. You can choose a [...]