Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedIn
Profile photo of Wojciech Galanciak
Wojciech Galanciak
Senior Eclipse Developer on the MyEclipse and Webclipse products.

Introduction

Two frameworks have emerged to simplify the development of RESTful web services and applications in Java—Jersey and RESTEasy. These frameworks are two of the most popular implementations of the JAX-RS standard. Both frameworks provide a nice feature set that simplifies the development of REST APIs. Sometimes the implementation is different, but their capabilities are very similar.

The purpose of this article is to compare the differences between the two frameworks. The focus is on features unique to each framework as well as features where the approaches differ significantly. The main goal is to provide some additional context for those who are trying to choose between the two. This document was created for RESTEasy 3.0.13 and Jersey 2.22.1.

Tip:  Refer to the Jax-RS documentation if you are just starting your journey with REST APIs in Java and would like more information.

Project Creation

The first step to start work with any kind of framework is to set up a project configuration. RESTEasy makes it easier to get started because it comes bundled with the following servers:

  • JBoss AS 7
  • JBoss EAP 6.1
  • Wildfly

Jersey is natively supported only by Glassfish.

Configuring Jersey

To have a better view, let’s assume our project is going to work in the Servlet 3.0 container environment. Jersey is built using Maven and also uses it extensively in project creation and configuration. There are two dedicated archetypes:

  • jersey-quickstart-grizzly2—for creating a standalone project that runs on top of a Grizzly container
  • jersey-quickstart-webapp—for creating web application skeletons

The grizzly2 archetype is a perfect way to start exploring Jersey capabilities. Execute the following command:

 

You get a new Jersey application out of the box:
JerseyApp

There are 3 different classes generated automatically:

  • MyResource—an example implementation of a resource
  • MyResourceTest—a JUnit test of this web service that utilizes a standalone Grizzly instance to provide an easy way to write JUnit tests for defined web services
  • Main—a class that uses the local Grizzly Container instance (by default on http://localhost:8080/myapp/) to expose services to test them with 3rd party tools

This project is perfect to learn about framework without struggling with server configuration and more complex project definition. Also, it does not require any knowledge about other Java web technologies.

The webapp archetype generates a web project with Jersey. Notice that it uses configuration through web.xml. We are focused on Servlet 3.0 so it is not required anymore.

Of course such example projects are useful only at the start. It is more common that RESTful services are added to an existing application or an application which implements a specific framework. In such cases configuration is also very simple. Jersey requires only one Maven dependency:

After this simple modification and Maven dependency resolution you can start implementing your resources with Jersey.

During project building you may see the following error:

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-war-plugin:2.2:war (default-war) on project simpleApplication: Error assembling WAR: webxml attribute is required (or pre-existing WEB-INF/web.xml if executing in update mode)

This is because we use Servlet 3.0 support where web.xml is no longer required. To avoid build failure on the missing web.xml file you need to add the following plugin to your build configuration in pom.xml:

Configuring RESTEasy

The situation is different in the case of RESTEasy. There are no official archetypes for getting started. In this case, configuration steps for an existing application and new project creation are the same. There is one main dependency required by RESTEasy:

As far as we consider our testing environment (Servlet 3.0 container) RESTEasy provides support for it via the ServletContainerInitializer integration interface. In this case one more dependency is required:

It is very important to add this dependency, otherwise our resources will not be accessible without any errors pointing to the possible cause.

Caching

Let’s start with a feature which is directly supported by only one of the frameworks. RESTEasy provides the following caching features:

  • Cache-Control header control
  • server-side in memory cache
  • client-side in memory cache

The first one is a set of two annotations—@Cache and @NoCache. They can be used only with @GET annotated methods. If such method has @Cache then for a successful response (with 200 OK response code) it automatically sets a Cache-Control header.

Here is an example usage of the @Cache annotation where we additionally require revalidation in the case of any POST/PUT/DELETE request on this resource:

The corresponding @NoCache annotation explicitly defines by Cache-Control: nocache header that we do not want anything to be cached.

The second caching feature is dedicated to RESTEasy Client API. It can be applied with both ClientRequest and Client Proxy Framework. In the case when response allows client to cache then it is cached in a local memory.

Here is a simple example of client-side caching with ClientRequest:

The last feature works on a server-side and is responsible for caching responses for GET method invocations. To enable it in the application an instance of org.jboss.resteasy.plugins.cache.server.ServerCacheFeature needs to be registered via Application.getSingletons() or Application.getClasses(). The direct access to the cache can be obtained by injecting org.jboss.resteasy.plugins.cache.ServerCache via the @Context annotation. Under the hood you will find the Infinispan library which provides the data storage mechanism for this caching feature.

What do we have in Jersey in this domain? Actually there is only a less elegant way for setting response headers. The following example is an equivalent to the @Cache annotation in RESTEasy:

Of course it is also possible to write the same annotation for Jersey. Learn how.

GZIP Compression

Although nowadays network speed may be very high, there are still areas where it may be limited. One example, and the most important, is a mobile world. Fortunately, a response body is usually just a text so it can be easily compressed on a server side and then decompressed on a client device. Let’s assume that we want to support communication both ways (compressed requests and responses) and that we want to selectively compress only those long enough responses.

RESTEasy provides out of the box support for GZIP compression and decompression. It means that if our service receives a request with Content-Encoding equals to gzip then such message body is decompressed automatically. The same situation is with a response—Content-Encoding header set to gzip triggers response body compression.  To avoid manual header configuration RESTEasy provides an @GZIP annotation:

The main downside of this approach is that gzip support can be defined only on methods level. It meets our requirement (applying selectively), but limits the flexibility.

Again in Jersey things need to be done more manually by using Interceptors API. Firstly, let’s fill a lack of @GZIP annotation with our own annotation:

This annotation allows us to bind a dedicated Gzip interceptor only to the specific methods:

This result interceptor is executed only for methods with an @Gzip annotation. In the same way, we may implement reader interceptor to decompress request body.

Testing

There are several ways to test your JAX-RS API. For example, you can perform real requests to a test server dedicated to the test environment. Or, you can use a lightweight standalone server on which livecycle is fully controlled directly from the test code. Another approach is to mock the server itself. Let’s see how testing is supported by our two frameworks.

RESTEasy does not provide a wide range of testing tools. The first one is a Mock Framework which applies the last approach mentioned above. Instead of sending a real request to the server, we are able to create mocks for both request and response and then pass them directly to a particular method. Here is an example how it works in practice:

There is also a set of plugins for RESTEasy which provides different embeddable servers. Unfortunately each has its own API and there is no unified way to use them in your tests.  This is where Jersey has a lot more to offer. It also has a set of extensions for different standalone containers, but more importantly, it provides something called Jersey Test Framework. How does it work? Here a simple example for UserResource:

This test will actually start a standalone test container. There are several different containers which can be used (a similar set is also supported by RESTEasy):

  • Grizzly
  • Jetty
  • HTTP Server from JDK
  • Simple
  • In Memory (not a real container – no network communication)

There are three ways to configure it:

  • do nothing—Jersey picks up TestContainerFactory from a classpath,
  • override JerseyTest#getTestContainerFactory() to define TestContainerFactory explicitly on the compilation level
  • set a system variable TestProperties#CONTAINER_FACTORY to move its declaration to the execution level

Note: It is possible to use TestNG instead of JUnit in Jersey Test Framework.

MVC

For the Model-View-Controller design pattern we can observe two completely different approaches. On one side there is generic MVC support in Jersey. On the other we have Spring integration in RESTEasy.

In Jersey architecture as a model we can consider returned value by a resource method, a controller is a resource class and a view is a template that consumes the model. We are already familiar with two of them, but what about a view? There are two ways to bind a model to a view—explicit and implicit.

The explicit approach utilizes the Viewable class which can be returned by a method, for example:

In the code above a User play instance is associated with a particular template. The implicit approach uses the @Template annotation instead:

The annotated method behaves in the same way as in the first approach, it returns a Viewable instance. Also in both cases the media type of a response is determined by the @Produces annotation.

In the case of the template engine there are several options available through extension modules:

  • Mustache
  • Freemarker
  • JSP (with some limitations)

As mentioned earlier, MVC support in RESTEasy is provided by Spring MVC integration. It can be applied by using Spring DispatcherServlet. The most important outcome is that Spring ModelAndView objects can be used as a return argument from GET resources. What is a downside in a comparison to Jersey? Definitely complexity level, especially when a developer is not familiar with the Spring Framework but would like to use MVC architecture.

Async API – Chunked Output

Since JAX-RS 2.0, asynchronous HTTP support has become a part of the specification through the @Suspended annotation and AsyncResponse interface. Both Jersey and RESTEasy provide their own implementation. The difference is that Jersey additionally provides something called Chunked Output. It allows the server to send back to the client a response in parts (chunks). This approach is very useful for long processing responses for which parts of data are available before the whole response data is prepared. In result, chunks can be pushed one by one to the client during request processing.

As you can see above, resource method returns ChunkedOutput just after the data processing thread is started.

Summary

Although we are looking at implementations of the same specification, both of them provide different additional features. If you are starting to learn JAX-RS, then Jersey provides some out of the box Maven archetypes to bootstrap development. On the other hand, RESTEasy is available in the JBoss server family by default. RESTEasy’s additional features focus on automation (caching and gzip support) to relieve a user from implementing some common capabilities for each application separately. However, Jersey has better testing infrastructure. It’s hard to pick a winner – the best approach is to make a decision based on what features and capabilities are important for your specific needs. Good luck!

Let Us Hear from You!

If you have any comments or questions, we would love to hear from you @MyEclipseIDE on twitter or via the MyEclipse forum

Related Posts

Introducing DevStyle – Rebooting EclipseR... Yesterday we released the first production version of DevStyle, a free add-on for Eclipse. DevStyle seeks to dramatically improve the Eclipse user experience for millions of developers with the introduction of modern developer ergonomics and the beautiful styling you’ve come to expect from products in 2017.Over the years, the Eclipse evolution has ...
30% off sale, including Angular IDE and more! Step away from the leftovers and come take advantage of our Cyber Monday sale for Angular IDE, Webclipse, MyEclipse and more!   Thanksgiving is a great time for getting together with family, but perhaps more importantly, it’s about the SALES!  Whether it’s Buen Fin or Cyber Monday, we all love a bargain. Now is the time to get the software you alwa...
Equifax Data Breach Advisory Many of you may have heard of the Equifax data breach, possibly affecting millions of consumers. Information accessed by hackers during the incident included Social Security numbers, personal details, driver’s license numbers, and even credit card numbers.Equifax has confirmed that the breach was made possible by a vulnerability in the Apache Strut...
Building Applications with Angular Material Angular Material is a set of high-quality UI components developed by the Angular team, based on the Google Material design specification. These components help us to build applications with an attractive, yet familiar UI, giving users a consistent experience across devices.In this Angular tutorial, you will learn how to set up material design in yo...

Posted on Nov 25th 2015