Just like many of you, we’ve been developing RESTful services for a while. We’ve used various frameworks in .NET and in Java, in large systems as well as on the server-side or our mobile apps. Unless there’s a good reason not to do so, REST is our preferred approach in building a service layer. Recently we’ve had a series of discussions about different approaches in building a RESTful service layer and I decided to outline one of the ways to do it using RESTEasy, Jackson, JSON and Spring Framework on the Java platform.
The following template project is Maven-based but I guess you can easily convert that to a Gradle project if you’d like to. At the end of it we are going to have an operation that’s just going to return a message wrapped in JSON and containing “Hello, World!”. I’m hoping to extend it by adding a MongoDB layer in a later post.
Domain
This is a very basic example. And our very simple Message
class resides in its separate Maven module called domain
. Here’s how Message
class looks like:
package ie.decaresystems.domain; public class Message { private String content; public Message(String aContent) { this.content = aContent; } @Override public String toString() { return content; } }
Services
The next thing we’re going to do is to reason in terms of services and not necessarily in terms of Web, HTTP or REST. This is going to be our second module: a service layer that is free from protocol and transport constraints. And this module is going to have dependency to the domain
module.
... <artifactId>services</artifactId> <dependencies> <dependency> <groupId>ie.decaresystems.rest</groupId> <artifactId>domain</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> ...
Our service interface is dead simple:
package ie.decaresystems.message; import ie.decaresystems.domain.Message; public interface Messenger { Message saySomething(String aType); }
So is its implementation:
package ie.decaresystems.message; import ie.decaresystems.domain.Message; public class SimpleMessenger implements Messenger { @Override public Message saySomething(String aType) { if ("hello".equalsIgnoreCase(aType)) { return new Message("Hello, World!"); } else { return new Message("What's up?"); } } }
RESTful Interface
At this point, we have two modules that we can unit-test without difficulty. Now, let’s expose the Messenger
interface using a RESTful approach. Let’s create a module that’s going to hold our Web layer.
... <modules> <module>domain</module> <module>services</module> <module>web</module> </modules> ...
I used the maven-archetype-webapp
archetype to create this module:
... -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-webapp ...
This creates pretty much the following pom.xml
(let’s take this opportunity to add the dependency to the services
module):
... <parent> <artifactId>SpringRestEasyTemplate</artifactId> <groupId>ie.decaresystems.rest</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>web</artifactId> <packaging>war</packaging> <name>Webapp</name> <dependencies> <dependency> <groupId>ie.decaresystems.rest</groupId> <artifactId>services</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> <build> <finalName>template</finalName> </build> ...
Now, let’s create our RESTful service interface inside the web
module.
package ie.decaresystems.rest; public interface Communication { }
As part of this simple project we’re going to create an operation accessible via the GET method and returning a greeting message wrapped in JSON. Let’s create a dependency to RESTEasy
as our JAX-RS implementation.
... <properties> <resteasy.version>3.0.6.Final</resteasy.version> </properties> ... <dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-jaxrs</artifactId> <version>${resteasy.version}</version> </dependency> ...
The operation that returns a simple message is going to be invoked through the GET method. It is going to produce a JSON response. And its path is going to be /messages/{type}
where type
is the type of the message (which is added to simply showcase the scenario where a parameter is passed in):
package ie.decaresystems.rest; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; public interface Communication { @GET @Path("/messages/{type}") @Produces(MediaType.APPLICATION_JSON) Response saySomething(@PathParam("type") String aType); }
The implementation of the Communication
interface is called Communicator
. It’s going to be accessed using the path /communicator
(that is in addition to the RESTEasy servlet prefix and Web app context, if any).
package ie.decaresystems.rest; import ie.decaresystems.domain.Message; import ie.decaresystems.message.Messenger; import ie.decaresystems.message.SimpleMessenger; import javax.ws.rs.Path; import javax.ws.rs.core.Response; @Path("/communicator") public class Communicator implements Communication { @Override public Response saySomething(String aType) { Messenger messenger = new SimpleMessenger(); Message message = messenger.saySomething(aType); return Response.ok(message).build(); } }
The saySomething()
method instantiates a SimpleMessenger
object and calls its saySomething()
method by passing the type that it receives from the REST client. Then, naively assuming that everything goes fine (because there’s no error handling etc.) it includes the returned Message
object as the entity of the response and returns a 200 OK
response.
The code above takes advantage of the static ok()
method of the Response
class. That line could also have been written, among others, using the following:
... return Response.status(Response.Status.OK).entity(message).build(); ...
Web Container Configuration
Now that our RESTful interface is ready, let’s configure our Web Container to run this example. Have a look at the following web.xml
file:
... <listener> <listener-class> org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap </listener-class> </listener> <context-param> <param-name>resteasy.scan</param-name> <param-value>true</param-value> </context-param> <context-param> <param-name>resteasy.servlet.mapping.prefix</param-name> <param-value>/api</param-value> </context-param> <servlet> <servlet-name>resteasy-servlet</servlet-name> <servlet-class> org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher </servlet-class> </servlet> <servlet-mapping> <servlet-name>resteasy-servlet</servlet-name> <url-pattern>/api/*</url-pattern> </servlet-mapping> ...
We’re using org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap
to bootstrap RESTEasy. It is a ServletContextListener
that creates a registry and configures a ProviderFactory. This is not the only way to bootstrap RESTEasy but I find it very easy this way.
You probably guessed it already: resteasy.scan
tells RESTEasy to automatically scan WEB-INF/lib
and WEB-INF/classes
directories for classes annotated with JAX-RS annotations such as @GET, @POST, @Path
, etc.
We, then, configure the dispatcher servlet that’s going to service the requests sent to our RESTful services. Here we picked /api
as the mapping however you’re free to choose whatever suits your needs.
When we build and deploy our WAR file to our Web Container we should see a similar message to the following line in our server console:
... PM org.jboss.resteasy.plugins.server.servlet.ConfigurationBootstrap INFO: Adding scanned resource: ie.decaresystems.rest.Communicator ...
This is clearly telling us that our Communicator interface is added to RESTEasy’s register. Because we have a single operation that can be invoked via a GET request you can use your browser to do it. In my case, I’m running my Tomcat on http://localhost:8080
and I deployed our application under the context called testapp
. Therefore my URL is: http://localhost:8080/testapp/api/communicator/messages/hello
.
It’s not necessary at this point however I would highly recommend you getting familiar with a tool that will quickly query your services. And I’m not only talking about GET requests but all the other possible methods. I’m a big fan of cURL. If you’re using cURL, you can use the following command:
curl -i -H "Accept: application/json" -X GET "http://localhost:8080/testapp/api/communicator/messages/hello"
With the above command you’ll be able to see the HTTP headers as well as the message returned by the server.
Alternatively if you are using Chrome, you can use Postman.
This is certainly not an exhaustive list of REST client tools that you can use. I used others in the past, such as SOAP UI, however I’m pretty happy with cURL and Postman. Please let us know if you are using another tool.
When we hit that URL, cURL returns an error:
From the headers, we can see that this is a server-side error. The message tells us that RESTEasy cannot turn our domain object (Message
) into JSON. Before we resolve this particular problem let’s see what happens if we hardcode a JSON response. Replace the body of the Communicator.saySomething()
method with the following single line:
return Response.ok("{type: \"" + aType + "\"}").build();
After refreshing our app we get the following response:
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: application/json
Content-Length: 15
Date: Tue, 11 Feb 2014 05:45:00 GMT
{type: "hello"}
Perfect! We get back a 200 OK
alongside the JSON message that we hardcoded. Now, let’s put back the Communicator.saySomething()
method the way it was previously and let’s resolve the MessageBodyWriter
problem that we encountered a few minutes ago.
Jackson
We are going to use Jackson as our JSON processor to marshall/unmarshall our objects. Jackson is a powerful and lightweight library. Ideally, once we configure it, it shouldn’t get in our way.
Let’s open our web
module’s pom.xml
and Jackson-enable our module:
... <dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-jackson-provider</artifactId> <version>${resteasy.version}</version> </dependency> ...
When we test our service we get back a 400 Bad Request
:
No serializer found for class ie.decaresystems.domain.Message and no properties discovered to create BeanSerializer...
This is happening because Jackson has no visibility on our Message
class’s content
field. We have a few options to remedy to that problem:
Getters & Setters
If we own the code that needs to be marshalled/unmarshalled then we can add getters and setters to the selected fields of our classes:
... public String getContent() { return content; } public void setContent(String content) { this.content = content; } ...
And we have the JSON representation of our Message object:
> curl -i -H "Accept: application/json" -X GET "http://localhost:8080/testapp/api/communicator/messages/hello" HTTP/1.1 200 OK Server: Apache-Coyote/1.1 Content-Type: application/json Transfer-Encoding: chunked Date: Tue, 11 Feb 2014 22:15:55 GMT {"content":"Hello, World!"}
Note that the Content-Type
is correctly set to application/json
. And if we pass in anything else than hello
then the response changes to:
> curl -i -H "Accept: application/json" -X GET "http://localhost:8080/testapp/api/communicator/messages/bonjour" HTTP/1.1 200 OK Server: Apache-Coyote/1.1 Content-Type: application/json Transfer-Encoding: chunked Date: Tue, 11 Feb 2014 22:20:07 GMT {"content":"What's up?"}
If you try these on Postman (the in-browser tool that I mentioned above) then you get the same thing on a nicer UI (which is definitely more practical in eyeballing the output when bigger data sets returned):
Clik here to view.

Postman – Headers
Clik here to view.

Postman – Beautified JSON response
Empty Beans
The previous error was generated because our Message class didn’t have any visible fields. If we don’t want to encounter this error during empty-bean processing then we can disable the SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS
property.
Field Visibility
We can also modify the visibility of the fields. By default Jackson will look for public getters and setters or public fields. However the following call will allow a more global detection of the fields regardless of their visibility:
... ObjectMapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY); ...
Service Injection using Spring Framework
Let’s add more flexibility to our application by loosening the coupling between our modules. Ideally we only want dependencies based on interfaces and not concrete classes.
@Path("/communicator") public class Communicator implements Communication { @Override public Response saySomething(String aType) { Messenger messenger = new SimpleMessenger(); Message message = messenger.saySomething(aType); return Response.ok(message).build(); } }
Above, the highlighted line contains the instantiation of our SimpleMessenger
service. I’d like to remove this and inject our Messenger
implementation using Spring.
Let’s first make the necessary modifications to Communicator.java
:
... private Messenger messenger; @Override public Response saySomething(String aType) { Message message = messenger.saySomething(aType); return Response.ok(message).build(); } public void setMessenger(Messenger messenger) { this.messenger = messenger; } ...
We created a private field of type Messenger and a public setter to inject an implementation. This way we remove our dependency on the concrete SimpleMessenger
class (new SimpleMessenger()
has disappeared).
Because we’re going to use Spring Framework to inject the required dependency, we need to find a way to declare Communicator
as a Spring-managed bean. There are many ways to do this. Here we’re going to use Spring’s @Service
annotation.
@Path("/communicator") @Service public class Communicator implements Communication { ...
We create a XML-based Spring configuration file. Following the convention and also ensuring auto-discovery, we name the configuration file applicationContext.xml
and we place it under WEB-INF
. In order to enable component auto-detection we use component-scan
. We also declare a concrete Messenger
instance as a Spring bean.
... <context:component-scan base-package="ie.decaresystems.rest"/> <bean id="messenger" class="ie.decaresystems.message.SimpleMessenger" /> ...
When it comes to injecting a bean into another there are many options. We are going to keep the configuration file lighter and take advantage of the @Resource
annotation in conjunction with the bean id that we used above:
... @Resource(name = "messenger") private Messenger messenger; ...
Because of Spring integration, our web.xml
gets its share of modification as well. RESTEasy comes with its own Spring ContextLoaderListener not-so-surprisingly called org.jboss.resteasy.plugins.spring.SpringContextLoaderListener
and we’re going to use it. We’re also going to turn off RESTEasy’s scanning (delete the entry completely), which was previously set to true
.
... <listener> <listener-class>org.jboss.resteasy.plugins.spring.SpringContextLoaderListener</listener-class> </listener> ...
Last but not least, let’s add the new dependencies to the Maven configuration file of our Web module:
... <properties> <resteasy.version>3.0.6.Final</resteasy.version> <spring.version>3.2.8.RELEASE</spring.version> </properties> ... <dependencies> ... <!--RESTEasy - Spring--> <dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-spring</artifactId> <version>${resteasy.version}</version> </dependency> <!--Spring--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> </dependencies>
When we build and run our little project we see the expected responses:
> curl -i -H "Accept: application/json" -X GET "http://localhost:8080/testapp/api/communicator/messages/hello" HTTP/1.1 200 OK Server: Apache-Coyote/1.1 Content-Type: application/json Transfer-Encoding: chunked Date: Thu, 13 Feb 2014 22:32:54 GMT {"content":"Hello, World!"} > curl -i -H "Accept: application/json" -X GET "http://localhost:8080/testapp/api/communicator/messages/bonjour" HTTP/1.1 200 OK Server: Apache-Coyote/1.1 Content-Type: application/json Transfer-Encoding: chunked Date: Thu, 13 Feb 2014 22:35:27 GMT {"content":"What's up?"}
Spring Framework 4.x
In the previous section we used Spring Framework 3.2. In a future blog post I’m going to describe the modifications necessary to make this solution work with Spring Framework 4.x.
Source Code
You can find this project’s source code on its GitHub Repository.
Image may be NSFW.
Clik here to view.
Clik here to view.
