I'm Solomon Duskis, NYC consultant and a Java/J2EE guy. I work at Sungard Consulting Services in NYC. The postings on this site are my own and do not necessarily represent the positions, strategies or opinions of my employer. Solomon is a DZone MVB and is not an employee of DZone and has posted 22 posts at DZone. You can read more from them at their website. View Full User Profile

Integrating JBoss RESTEasy and Spring MVC

10.15.2009
| 99424 views |
  • submit to reddit

Jetty

Running Jetty is rather simple. You've seen most of the details of the pom.xml when we previously discussed it. Running jetty through maven involves running the following command:

mvn jetty:run
(If you haven't done so already, download the file as a tar ball, and change the pom.xml's version of the two RESTEasy dependencies to 1.2.RC1)

That command will launch Jetty, and allow you to browse our project at http://localhost:8080/contacts. Add a few contacts, and view them either as a group at /contacts in HTML, as a group in XML at /contact/data, or individually as XML by following the links found at /contacts.

Congratulations. You now have a running Spring MVC/RESTEasy application. We need one more thing to consider this application complete: a JUnit test.

ContractTest.java

RESTEasy provides a mechanism for easily launching a Spring MVC/RESTEasy application. RESTEasy also comes with a robust REST client framework. This article will cover bits and pieces of the test, but you can view the entire code in the RESTEasy SVN.

To start, we're going to set up an interface that the RESTEasy client can use to create a client for our application. It consists of abstract methods annotated with JAX-RS annotations:

  @Path(ContactsResource.CONTACTS_URL)
public interface ContactProxy {
@Path("data") @POST @Consumes(MediaType.APPLICATION_XML)
Response createContact(Contact contact);

@GET @Produces(MediaType.APPLICATION_XML)
Contact getContact(@ClientURI String uri);

@GET
String getString(@ClientURI String uri);
}

 

All methods on ContactProxy inherit the ContactsResource.CONTACTS_URL path ("/contacts") as the root URL, just like a server-side JAX-RS resource. This interface's has three methods:

  • Create a contact - the createContact method maps to a POST to "/contacts/data". The method accepts a Contact object which will be converted to XML before it's sent to the server. The result is a JAX-RS Response object which contains the response status and headers. One of those headers includes the LOCATION of the new contact
  • Get an XML Contact - Given a URL to a Contact, such as the URL returned by the createContact method's response's LOCATION header, GET an XML response and create a Contact object from it.
  • Get a Response as a String - Given a URL, such as a Contact URL or anything else on the server, retrieve a String result.

This interface will be used by RESTEasy to construct a concrete instance that uses the JAX-RS annotations to perform the actual HTTP calls. Next, let's create the embedded server and use RESTEasy to create that instance of a ContactProxy:

  private static ContactProxy proxy;

private static TJWSEmbeddedSpringMVCServer server;
public static final String host = "http://localhost:8080/";

@BeforeClass
public static void setup() {
server = new TJWSEmbeddedSpringMVCServer("classpath:springmvc-servlet.xml", 8080);
server.start();

RegisterBuiltin.register(ResteasyProviderFactory.getInstance());
proxy = ProxyFactory.create(ContactProxy.class, host);
}

@AfterClass
public static void end() {
server.stop();
}

JUnit invokes methods annotated by @BeforeClass before any test methods run. Methods annotated by @AfterClass are triggered by JUnit before after all test methods are complete. In our case, the setup method will instantiate a server that contains a SpringMVC Servlet on port 8080 that is configured by the same Spring XML configuration file we used in Jetty. It also invokes the two lines of code required to create a RESTEasy client. RegisterBuiltin sets up the RESTEasy run time, and must be run one time per client. ProxyFactory.create tells RESTEasy to read the annotations on the ContactProxy interface and to create a Java Proxy instance that knows how to perform the HTTP requests we'll need for our test:

  @Test
public void testData() {
Response response = proxy.createContact(new Contact("Solomon", "Duskis"));
String duskisUri = (String) response.getMetadata().getFirst(HttpHeaderNames.LOCATION);
Assert.assertTrue(duskisUri.endsWith(ContactsResource.CONTACTS_URL + "/data/Duskis"));
Assert.assertEquals("Solomon", proxy.getContact(duskisUri).getFirstName());
...
}

This test creates a new Contact, checks the server's response to make sure that the URL is consistent with the test's expectations. It then re-retrieves the Contact and confirms that the firstName is indeed what was sent sent in. While this is a pretty trivial looking test, it performs quite a bit of HTTP activity and business logic.

Conclusion

This article discussed quite a bit of philosophy and design considerations in building a RESTful web application with RESTEasy and Spring MVC. We also built an end to end application with RESTEasy, Spring MVC, Maven, Jetty and JUnit. Even though the content in this article was significant, the code presented here is relatively short compared to other Java alternatives. We touched on subjects like designing REST Applications, creating Spring applications, the RESTEasy client infrastructure and testing RESTful applications. Each of those subjects merit their own articles. There were also other subjects that we simply couldn't fit into this article (as long as it is), including JavaScript to the toolkit to allow closer integration between the browser and your RESTful application, integrating with Flex and more. The code presented in this article can serve as a spring board (again, no pun intended) for all of those ideas.

About the Authors

Solomon Duskis

Solomon Duskis is a Senior Manager at SunGard Consulting Services. He's been developing for 22 years -- 12 years in professional capacity. He has experience in various industries such as Finance, Media, Insurance and Health. He contributes to Open Source projects such as JBoss Resteasy and the Spring framework. He is a published author of Spring Persistence - A Running Start, and the upcoming book Spring Persistence with Hibernate.

Richard Burton

Richard Burton is the co-founder of a small independent consulting firm called SmartCode LLC. He is an Open Source fanatic with over 10 years of experience in various industries such as Automotive, Insurance, Finance and fondly remembers the .com era. In his spare time, he contributes to Open Source projects such as SiteMesh 3, Struts 2, and more.

Reference

REST

 

JAX-RS


RESTEasy
Spring
Spring MVC
Published at DZone with permission of Solomon Duskis, author and DZone MVB.

(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

Thanks !

Seb Cha replied on Wed, 2009/11/04 - 12:16pm

Good JAX-RS tutorial !

Tony Childs replied on Sat, 2010/05/01 - 9:58am

Thanks for the great article. There is something I have not been able to figure out, however.

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

After further examination of the startup behavior I managed to figure out a way to get the mappings in there. I copied your springmvc-resteasy.cml file and used it as a template for my own custom file. I then added/changed the folloing lines:

<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

Great Article! If any of you run into the following issue: "No mapping found for HTTP request with URI [/main/blog/list] in DispatcherServlet with name 'spring' ERROR org.jboss.resteasy.springmvc.ResteasyHandlerMapping - Resource Not Found: Could not find resource for relative Then all you have to do is modify your spring app context xml file: Add these 2 lines: (I am omitting the cone opening and closing cone brackets, as they do not appear here for some reasons: context:component-scan base-package="com.zyrisinc.googlecheckout.service" bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" property name="order" value="0" bean bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"

Pasta Farian replied on Wed, 2010/09/22 - 2:44pm

Update: I can access it by going to http://localhost:8080/examples-resteasy-springMVC-2.1-SNAPSHOT/contacts but when I try to add a contact, I end up back on http://localhost:8080/contacts which gives me a 404 and apparently no contacts were added. By the way, with Tomcat I needed to add jstl.jar to the runtime. ----- Hi, Great article. Very helpful. I am having trouble running this WAR on Tomcar 6. The WAR deploys without any errors but when I go to http://localhost:8080/contacts I get a HTTP 404. Can anyone deploy this on Tomcat successfully? or do I need to make some changes to the servlet mapping? Thanks.

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

 

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.