Integrating JBoss RESTEasy and Spring MVC
ContactsResource.java
MVC Controllers control the flow between the Model and the View. Resource is REST's equivalent to Controllers, and we'll be using the term Resource and Controller interchangably. In our case, our resource handles requests to /contracts and /contracts/{id}. Our ContractsResource must perform quite a few functions on those two URL templates:
- Retrieve all Contacts - Display the results in either HTML, XML or JSon. For clarity, we'll break out the data oriented functionality (XML and JSon) from the user oriented functionality (HTML) into two distinct URLs - /contacts for HTML and /contacts/data for XML and JSon. REST allows a client to select which format it prefers to receive the data in through a process called Content Negotiation. Content Negotiation can happen through HTTP headers, URI or query parameters. Our ContractsResource will use different URIs to differentiate between data oriented and user views, and will use HTTP headers to differentiate between XML and JSon data views.
- Save a Contact - Create or Updating data is a pretty standard requirement. The Save a Contact functionality mirrors the Content Negotiation needs of Retrieve all Contacts. User oriented data exchange comes in the form of HTML form data, and data oriented exchange usually occurs in XML and JSon. These differing requirements require ContractResource to have two distinct JAX-RS Java methods; we'll also separate the URLs for clarity purposes.
- View a Contact - We'll create a single view for viewing a single contact that returns XML or JSon. We leave the user oriented view as an exercise for the reader.
Here's another view of our requirements:
| Functionality | URL | Format | Java Method |
| User Oriented View All | /contacts | HTML | viewAll() |
| Data Oriented View All | /contacts/data | XML or JSon | getAll() |
| User Oriented Save | /contacts/ | Form data | saveContactForm() |
| Data Oriented Save | /contacts/data | XML or JSon | saveContact() |
| Data Oriented View Single | /contacts/data/{lastName} | XML or JSon | get() |
Note that we mixed and matched HTML and data oriented functionality in this requirement. Now that we have our requirements in place, let's take a look at the ContactsResource code. There are quite a few new Spring and JAX-RS annotations which we'll explain right after the code:
@Controller
@Path(ContactsResource.CONTACTS_URL)
public class ContactsResource
{
public static final String CONTACTS_URL = "/contacts";
@Autowired
ContactService service;
@GET
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
@Path("data")
public Contacts getAll() {
return service.getAll();
}
@GET
@Produces(MediaType.TEXT_HTML)
public ModelAndView viewAll() {
// forward to the "contacts" view, with a request attribute named
// "contacts" that has all of the existing contacts
return new ModelAndView("contacts", "contacts", service.getAll());
}
@PUT
@POST
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
@Path("data")
public Response saveContact(@Context UriInfo uri, Contact contact)
throws URISyntaxException {
service.save(contact);
URI newURI = UriBuilder.fromUri(uri.getPath()).path(contact.getLastName()).build();
return Response.created(newURI).build();
}
@POST
@PUT
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.TEXT_HTML)
public ModelAndView saveContactForm(@Form Contact contact)
throws URISyntaxException {
service.save(contact);
return viewAll();
}
@GET
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
@Path("data/{lastName}")
public Contact get(@PathParam("lastName") String lastName) {
return service.getContact(lastName);
}
}
This code is packed with annotations and Java code that's indicative of JAX-RS Resources and Spring applications. There is also a RESTEasy custom annotation.
The Spring IoC annotations are well documented, but we are using them in unusual ways for our integration:
- @Controller tells the Spring runtime that it needs to create an instance of ContractsResource at startup time. Do you remember the component-scan directive that was used in the Spring configuration section? The combination of the directive and the annotation tell Spring that a singleton instance of ContractsResource must be created at startup. Spring has a more generic @Component, but the use of @Controller allows for more precise definition of bean usage and also allows for future upgrades that involve AoP to create more precise targeting. While @Controller is usually associated with Spring @MVC annotated controllers and not other Controller infrastructures, but even thought it's not a Spring MVC controller, we use it to tell Spring that this indeed is a Controller That association of @Controller to Spring MVC annotated controllers is a loose coupling in the Spring runtime. We'll use JAX-RS annotations to configure the handling of URL and HTTP handling behavior. You could theoretically add additional Spring @MVC annotations such as @RequestMapping (which is an equivalent of JAX-RS @Path) to our ContactsResource, if you really wanted to
- @Autowired tells the Spring runtime that instances of ContractResource require an instance of ContactService. We'll be coding the ContactService later in this article. You can take a look at the Spring reference documentation for more information about @Autowired and @Controller.
- The last Spring artifact that we use is ModelAndView: It is Spring MVC's encapsulation of which logical View to use and which Model variables should be passed into the View. In our case, we're going to create a Model variable called "contacts" that is a List of all Contact objects we have in the system. We're passing that variable to the a logical view named "contacts" which will map to "/WEB-INF/contacts.jsp" based on the Spring configuration that we previously discussed.
The JAX-RS annotations are also well documented, but it's definitely worth while to give a brief overview:
- @Path tells the RESTEasy (or other JAX-RS environments) how to map URLs to java methods. Adding @Path at the class level tells, in our case "/contacts", indicates that all methods must be prefixed with that URL. The @Path value can either be a hard coded URL such as "/contacts" or it can be a URI template such as "data/{lastName}". You can even specify regular expressions for more sophisticated filtering in the URI template.
- @GET, @PUT and @POST are used in combination with @Path to indicate which specific HTTP methods are handled by individual Java methods
- @Produces and @Consumes are
used to further filter how a request should be handled based on content
negotiation based on the Accept and Content_Type HTTP header. JAX-RS
provides a set of default mime type values in the MediaType class.
- @PathParam is a method parameter annotation that indicates how a URI template variable is mapped to a method parameter. There are quite a few other method parameter level annotations that you could use to map HTTP headers, cookies, query parameters and form parameters to member variables
- @Context is an interesting JAX-RS parameter that allows dependency injection of request level information such as HttpRequest, HttpResponse and UriInfo (which as you can probably guess encapsuldates information about the request URI). It's important to note that Spring by default manages beans such as ContactsResource as a singleton; if ContactsResource was a Prototype or Request scoped bean, you would be able to use the @Context annotation on member variables in addition to method variables. For more on Spring scoping see the Spring Framework documentation.
The last annotation we need to talk about is @Form. It's a RESTEasy custom annotation that describes that a member variable encapsulates data from HTML forms. If you recall, we used the JAX-RS @FormParam annotation on our Contact domain object. @Form and @FormParam are used in concert to allow for better maintenance of form based processing systems. JAX-RS 2.0's stated goals include a more robust, uniform Form processing annotation system.
The functionality to code ratio is pretty high because of all of the declarative coding conventions of these annotations.
Now that we've discussed the most involved pieces of the puzzle, let's take a look at completing the project.
Additional Artifacts
pom.xml
Our pom.xml includes dependency management, description of required Maven repositories, a description of which JDK we're going to use and a Jetty web server configuration. We'll cover the repository selection, the dependencies specific to RESTEasy and a jetty-maven integration
External Repositories
<repositories>
<repository>
<id>jboss</id>
<name>jboss repo</name>
<url>http://repository.jboss.org/maven2</url>
</repository>
<repository>
<id>scannotation</id>
<url>http://scannotation.sf.net/maven2</url>
</repository>
<repository>
<id>java.net</id>
<url>http://download.java.net/maven/1</url>
<layout>legacy</layout>
</repository>
<repository>
<id>maven repo</id>
<name>maven repo</name>
<url>http://repo1.maven.org/maven2/</url>
</repository>
</repositories>
Project Dependencies
Now that we've informed Maven which additional repositories are required, we can now include the dependencies the our sample project will require. The <dependencies/> section of the pom.xml file, should include the following two dependencies for Spring and RESTEasy functionality - resteasy-spring and resteasy-jaxb-provider:<dependencies>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-spring</artifactId>
<version>1.2.RC1</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxb-provider</artifactId>
<version>1.2.RC1</version>
</dependency>
<dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<version>6.1.15</version>
<scope>test</scope>
</dependency>
<!-- Other dependencies ... -->
</dependencies>
The resteasy-spring dependency includes the adapter that integrates RESTEasy into Spring's MVC and provides most the required Java dependencies for RESTEasy and Spring. It also contains Spring configuration needed within the embedded spring-resteasy.xml file that will be used in the Spring configuration section. The other RESTEasy dependency that's included, resteasy-jaxb-provider, contains classes that convert the payload into various formats before sending it to the client.
The last dependency to focus on is the maven-jetty-plugin which allows us to easily startup our project in a Jetty webserver environment.
Note: If you're follow the link above to the RESTEasy repository's version of pom.xml, you will have to modify the version of resteasy-spring and resteasy-jaxb-provider to the latest version that has been deployed, specifically 1.2.RC1 at the time this article was written. The RESTEasy repository contains a soon-to-be-deployed version number which will not work unless you build the entire RESTEasy project.
Maven Jetty Plugin
One last interesting item of pom.xml is the configuration of the Jetty web server<build>
<finalName>resteasy-springMVC</finalName>
<plugins>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<version>6.1.15</version>
<configuration>
<contextPath>/</contextPath>
<scanIntervalSeconds>2</scanIntervalSeconds>
</configuration>
</plugin>
...
</plugins>
</build>
This will allow us to startup Jetty against localhost:8080. You can learn more about the maven Jetty plugin and a variety of configuration options.
Let's start with the domain model and move on to the service object. From there, we'll discuss the JAX-RS Resource/Controller. From there, we'll explore the unit test and finally we'll write the JSP View and start up our server.
Contact.java
Our DTO is going to be deceptively simple. It will perform a dual responsiblity of JAXB XML binding and Form parameter binding. Both sets of functionality will be configured through annotations and will be managed through JAXB and JAX-RS:import javax.ws.rs.FormParam;
import javax.xml.bind.annotation.XmlRootElement;
@XMLRootElement
public class Contact {
private String firstName, lastName;
// default constructor for JAXB (also required by JPA/Hibernate if you use them)
public Contact(){}
// helper constructor for our Controller/Service operations
public Contact(String firstName, String lastName){
this.firstName = firstName;
this.lastName = lastName;
}
@FormParam("firstName")
public void setFirstName(String firstName) { this.firstName = firstName; }
public String getFirstName() { return firstName; }
@FormParam("lastName")
public void setLastName(String lastName) { this.lastName = lastName; }
public String getLastName() { return lastName; }
// equals and hasCode are added for the Map based Service object
public boolean equals(Object other){ .. }
public long hashCode(){ .. }
}
The annotation on the setters tells JAX-RS to bind any incoming form parameters to the appropriate setter. The @XMLRootElement annotation is enough to tell JAXB that the Contract object must be bound to getters and setters must be bound to an XML document that will look like:
<contact>
<firstName>Richard</firstName>
<lastName>Burton</lastName>
</contact>
The Contacts class is a simple wrapper around a List of Contact instances:
@XmlRootElementContacts has the @XmlRootElement, just like Contact. The @XmlRootElement annotation tells JAXB to transform objects of this type to an XML structure that has <contacts> as its top level element. In addition, we've added the @XmlElement annotation to the getContacts() method. By default, JAXB renders all JavaBean elements and uses the JavaBean name as the element. JAXB handles Lists as special cases: all List elements are translated to XML elements using the JavaBean name. @XmlElement(name="contact") tells JAXB that we opted to override the default name ("contracts") in favor of our own name ("contract" - no 's').
public class Contacts {
private Collection<Contact> contacts;
public Contacts() {
this.contacts = new ArrayList<Contact>();
}
public Contacts(Collection<Contact> contacts) {
this.contacts = contacts;
}
@XmlElement(name="contact")
public Collection<Contact> getContacts() { return contacts; }
public void setContacts(Collection<Contact> contact){ this.contacts = contact; }
}
The Contracts object will bind to XML that looks like:
<contracts>
<contract>
<firstName>Richard<firstName>
<lastName>Burton</lastName>
</contract>
<contract>
<firstName>Solomon<firstName>
<lastName>Duskis</lastName>
</contract>
</contracts>
Now that we have our Domain model in place, let's start using it in our Service tier.
ContactService.java
Since the purpose of this article is JAX-RS centric, we're not going to create an elaborate service layer, but we'll add once since creating more robust Spring applications do require service or data access layers. If you're interested in seeing a RESTEasy/Spring application with database access, look here. Our ContractService performs simple in-memory storage of Contacts by last name:@ServiceThere are two items of interest that are noteworthy:
public class ContactService
{
private Map<String, Contact> contactMap = new ConcurrentHashMap<String, Contact>();
public void save(Contact contact){ contactMap.put(contact.getLastName(), contact); }
public Contact getContact(String lastName){ return contactMap.get(lastName); }
public Contacts getAll() { return new Contacts(contactMap.values()); }
}
- Notice the use of Spring's @Service annotation. Do you remember the component-scan directive that was used in the Spring configuration section? The combination of the directive and the annotation tell Spring that a singleton instance of ContractService must be created at startup. Spring has a more generic @Component, but the use of @Service allows for more precise definition of bean usage and also allows for future upgrades that involve AoP to create more precise targeting.
- Notice the use of ConcurrentHashMap. It's a JDK 1.5 addition that adds performance in multi-threaded environments. It's an easy way to boost performance in distributed REST applications
Next, let's take a look at the JSP that
contacts.jsp
We've explored the Model and Controller aspects of MVC. The last piece to the puzzle is the View. Most JAX-RS based interactions perform a more automated conversion of objects like our Contact to a data-oriented view, such as XML or JSon. Traditionally, Java EE MVC has been done with a more manual View management with languages such as JSP. Our JSP will take a Contracts instance created in ContractsResources.viewAll() and render it in basic HTML:
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<body>
<h2>Hello Contacts!</h2>
<div id="contact-data" class="contacts">
<c:forEach var="contact" items="${contacts.contacts}">
<span class="contact">Hello <a href="/contacts/data/${contact.lastName}">${contact.firstName} ${contact.lastName}</a></span>
</c:forEach>
</div>
<p>Save a contact, save the world:</p>
<form action="/contacts" method="post">
First Name: <input type="text" name="firstName" /><br>
Last Name: <input type="text" name="lastName" /><br>
<input type="submit" value="submit"/>
</form>
</body>
</html>
This JSP loops over all contacts and adds links to their data-oriented View. It also creates a simple HTML form for creating a new Contact. While this JSP is simple, it will help us exercise three of our ContactsResource Controller: viewAll(), .saveContactForm(), and get(). It could also be a spring board for more complicated AJAX/JSon interaction, but that's beyond the scope of this article.
The code and configuration is now complete, so let's run this project!
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)






Comments
christophe charles replied on Fri, 2009/10/23 - 6:52am
Seb Cha replied on Wed, 2009/11/04 - 12:16pm
Tony Childs replied on Sat, 2010/05/01 - 9:58am
Without Spring integration the RestEasy ConfigurationBootstrap.createDeployment() method adds any RestEasy context params - more specifically "resteasy.media.type.mappings" to map type extensions to MIME types.
Unfortunately, when Spring is integrated, these mappings are not picked up. I have been stepping through the code trying to figure out how I might be able to pass these context params to RestEasy when I noticed you had authored some classes in the Resteasy-Spring integration package, so I thought you might be the best person to ask. What would be the best way to get these mappings to RestEasy?
Thanks, Tony
Tony Childs replied on Sat, 2010/05/01 - 11:02am
<bean id="jsonType" class="javax.ws.rs.core.MediaType" factory-method="valueOf"> <constructor-arg value="application/json"/> </bean> <bean id="xmlType" class="javax.ws.rs.core.MediaType" factory-method="valueOf"> <constructor-arg value="application/xml"/> </bean> <bean id="resteasy.dispatcher" class="org.jboss.resteasy.core.SynchronousDispatcher" depends-on="resteasy.intializer"> <constructor-arg ref="resteasy.providerFactory"/> <property name="mediaTypeMappings"> <map> <entry key="json" value-ref="jsonType"/> <entry key="xml" value-ref="xmlType"/> </map> </property> </bean>Suresh Bhaskaran replied on Fri, 2010/08/27 - 7:53pm
in response to:
christophe charles
Pasta Farian replied on Wed, 2010/09/22 - 2:44pm
Clay Press replied on Sun, 2011/10/16 - 11:07pm
Two Years After, this jboss/resteasy/spring/maven tutorial still builds and tests as advertised. Nice demo.
Will java rest keep pace with the dynamic type competitive alternatives in the POST-sun.com era? Which decision trumps: resteasy vs jersey vs spring vs restlet <or> java/c@ vs python/ruby.
Two Years Later, where will java rest be