You Should Use JAXB Generated Classes for RESTful Web Services
Learn how to build RESTful web services in Spring that can utilize either JSON or XML.
Join the DZone community and get the full member experience.
Join For FreeI remember in the late 90s / early 2000 all the buzz in programming was about XML. All the ‘experts’ said you had to be using XML for data exchange. XML does have many benefits. But often when programming today, XML is looked as ‘old school’ or too restrictive. XML sure can be finicky to work with. Many developers when given a choice (including myself) will use JSON over XML. JSON is much more forgiving than XML is, which makes it simpler to work with.
While XML may be old school, it still can be good to use. Even when you’re doing JSON based Restful web services.
Restful Web Services in Spring
I’m not going to cover building Restful Web Services in Spring in this post. That’s a future topic. But when you’re using Spring MVC to develop Restful Web Services, you can set up a lot of flexibility. I typically design my web services so the client can use JSON or XML. The standards support this, and it’s fairly easy to do.
Many of the examples you will see on the internet will start with using JAXB annotated Java POJOs. This works, but I also feel this is a mistake. The ‘contract’ for your web services is now a Java class. Which may work for you, but it’s not portable. What if one of your clients is writing in PHP? A JAXB annotated Java class is useless to them.
XML Schema
XML Schema is a specification for describing XML documents. Think of it as strong typing for an XML document. You can specify the properties, if they can be null, their data types, if they can be a list, etc. The capabilities of XML schema is very robust.
A really cool feature of JAXB is you can generate JAXB annotated Java POJOs from a XML Schema document. And when you do this, you now have a portable contract for the data types of your web services. Your ‘contract’ is no longer tied to the Java programming language. You could give the XML schema to someone building a client for your web service in another programming language, like C# maybe, and they can use the XML Schema to generate code for the client.
XML Schema is a widely accepted standard that is not tied to a specific programming language. By using XML schema and providing it to your clients you make your Restful Web Service easier to consume. Your clients have a standardised specification of exactly what they need to send.
JAXB Generated Classes for Restful Web Services
In this post, I’m going to show you how to setup a Maven project to create a Jar file of Java classes generated by JAXB from an XML Schema.
Generating a Maven Project in IntelliJ
For the purposes of this example, I’m going to use IntelliJ to create a Maven project. In real use, you’ll want to set this up as either a independent Maven project, or a Maven module. This will allow the JAXB generated classes to be bundled in a JAR file and reused in other projects or modules.
1. Create a new project in IntelliJ.
2. Set the GroupId and ArtifactId in the New Project dialog of IntelliJ.
3. Select where to store the project on your drive.
4. IntelliJ will as your to verify the creation of a new directory. Click OK.
5. Depending on your settings in IntelliJ, you may be asked to import changes. I often keep this feature off when dealing with large complex Maven projects due to performance reasons. If you see this dialog, click on ‘Import Changes’.
6. At this point you’ve created a new Maven project in IntelliJ. You can see the Maven standard directory structure has been created.
Create the XML Schema
The first file we will create is the XML Schema we will be using. Let’s say we’re creating a Web Service to add a product, and need a create product command object.
In our XML Schema we are creating a Product class, and the a CreateProductRequest class too. This is going to extend the ProductClass and add a field for the API key. This file is placed in the folder /main/resources. This is the default location for XML Schema files.
jaxb.xsd
<?xml version="1.0"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" jaxb:version="2.0">
<!--This tells JAXB what package to create the Java classes in-->
<xsd:annotation>
<xsd:appinfo>
<jaxb:schemaBindings>
<jaxb:package name="guru.springframework.domain"/>
</jaxb:schemaBindings>
</xsd:appinfo>
</xsd:annotation>
<xsd:complexType name="Product">
<xsd:sequence>
<xsd:element name="productId" type="xsd:integer"/>
<xsd:element name="productDescription" type="xsd:string"/>
<xsd:element name="productPrice" type="xsd:decimal"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CreateProductRequest">
<xsd:complexContent>
<xsd:extension base="Product">
<xsd:attribute name="apikey" type="xsd:string"/>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>
Configure Maven
Creating the project in IntelliJ gave us a very basic Maven POM file. Here is the Maven POM created for us.
<?xml version="1.0" encoding="UTF-8"?>
<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>guru.springframework</groupId>
<artifactId>jaxb-xsd-example</artifactId>
<version>1.0-SNAPSHOT</version>
</project>
Maven Dependencies
We need to add three dependencies to our Maven POM. This first is the JAXB API, the second is the JAXB implementation, and finally the third is for the Maven JAXB plugin.
<dependencies>
<!--jaxb support-->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.2.12</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.2.11</version>
</dependency>
</dependencies>
Maven JAXB Plugin
Next we need to configure the JAXB plugin for Maven to the Maven POM.
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>0.12.3</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
</plugin>
Complete Maven POM
Here is the final Maven POM.
<?xml version="1.0" encoding="UTF-8"?>
<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>guru.springframework</groupId>
<artifactId>jaxb-xsd-example</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!--jaxb support-->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.2.12</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.2.11</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>0.12.3</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Building Our JAXB Maven Project
Running the Maven Package Goal
IntelliJ makes working with Maven very easy. On the right side of the IDE, you’ll see a button for ‘Maven Projects’, clicking that will open the ‘Maven Projects’ dialog. To build our project, under Lifecycle, double click on the ‘package’ goal.
You should see Maven run and build successfully.
[INFO]
[INFO] --- maven-jar-plugin:2.3.2:jar (default-jar) @ jaxb-xsd-example ---
[INFO] Building jar: /Users/jt/src/springframework.guru/blog/jaxb-xsd-example/target/jaxb-xsd-example-1.0-SNAPSHOT.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.410s
[INFO] Finished at: Fri Aug 07 07:23:44 EDT 2015
[INFO] Final Memory: 16M/207M
[INFO] ------------------------------------------------------------------------
Maven Build Artifacts
Maven will build into the ‘Target’ directory. You can see the Java classes generated in IntelliJ.
JAXB Generated Classes
We expected two classes generated from the XML Schema we defined.
Product.java
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.11
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2015.08.07 at 07:23:43 AM EDT
//
package guru.springframework.domain;
import java.math.BigDecimal;
import java.math.BigInteger;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.bind.annotation.XmlType;
/**
* <p>Java class for Product complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* <complexType name="Product">
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* <element name="productId" type="{http://www.w3.org/2001/XMLSchema}integer"/>
* <element name="productDescription" type="{http://www.w3.org/2001/XMLSchema}string"/>
* <element name="productPrice" type="{http://www.w3.org/2001/XMLSchema}decimal"/>
* </sequence>
* </restriction>
* </complexContent>
* </complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Product", propOrder = {
"productId",
"productDescription",
"productPrice"
})
@XmlSeeAlso({
CreateProductRequest.class
})
public class Product {
@XmlElement(required = true)
protected BigInteger productId;
@XmlElement(required = true)
protected String productDescription;
@XmlElement(required = true)
protected BigDecimal productPrice;
/**
* Gets the value of the productId property.
*
* @return
* possible object is
* {@link BigInteger }
*
*/
public BigInteger getProductId() {
return productId;
}
/**
* Sets the value of the productId property.
*
* @param value
* allowed object is
* {@link BigInteger }
*
*/
public void setProductId(BigInteger value) {
this.productId = value;
}
/**
* Gets the value of the productDescription property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getProductDescription() {
return productDescription;
}
/**
* Sets the value of the productDescription property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setProductDescription(String value) {
this.productDescription = value;
}
/**
* Gets the value of the productPrice property.
*
* @return
* possible object is
* {@link BigDecimal }
*
*/
public BigDecimal getProductPrice() {
return productPrice;
}
/**
* Sets the value of the productPrice property.
*
* @param value
* allowed object is
* {@link BigDecimal }
*
*/
public void setProductPrice(BigDecimal value) {
this.productPrice = value;
}
}
CreateProductRequest.java
Notice how this class actually extends the Product class.
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.11
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2015.08.07 at 07:23:43 AM EDT
//
package guru.springframework.domain;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlType;
/**
* <p>Java class for CreateProductRequest complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* <complexType name="CreateProductRequest">
* <complexContent>
* <extension base="{}Product">
* <attribute name="apikey" type="{http://www.w3.org/2001/XMLSchema}string" />
* </extension>
* </complexContent>
* </complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "CreateProductRequest")
public class CreateProductRequest
extends Product
{
@XmlAttribute(name = "apikey")
protected String apikey;
/**
* Gets the value of the apikey property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getApikey() {
return apikey;
}
/**
* Sets the value of the apikey property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setApikey(String value) {
this.apikey = value;
}
}
Conclusion
This is just a very simple example of generating classing from an XML Schema using JAXB and Maven. In this post, I’ve shown you step by step how to use an XML Schema and JAXB to generate Java classes. The generated classes are bundled into a JAR file, which is portable and can be shared with other Java projects.
As a Spring Source consultant, I was at a large company which built a number of Restful APIs. The team building the APIs did not use JAXB to generate classes from an XML Schema. Rather they built the JAXB classes by hand and could not offer their clients an XML Schema. As a consumer of their APIs, it was a time consuming process to configure and troubleshoot my data types.
I’ve also done consulting in organizations where the team did use XML Schemas for building their APIs. Having the XML Schema made writing the client code a snap.
Resources
JAXB
You can find the documentation for the JAXB project here.
JAXB Maven Plugin
I used the default settings for the JAXB Maven plugin. Additional options are available. Documentation for the JAXB Maven plugin is here.
Project Source Code
The source code used in this tutorial is available on Github here.
Published at DZone with permission of John Thompson, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments