Monday, January 20, 2014

Migrating Spring MVC RESTful web services to Spring 4

1   Introduction


Spring 4 brings several improvements for MVC applications. In this post I will focus on restful web services and try these improvements by taking a project implemented with Spring 3.2 and upgrading it to Spring 4. The following points sum up the content of this post:

The source code of the following projects can be found at github:

Original project (spring 3.2)

Migration to Spring 4


2   The Spring 3.2 RESTful sample


The starting project is implemented with Spring 3.2 (pom.xml) . It consists in a Spring MVC application that access a database to retrieve data about TV series. Let's have a look at its REST API to see it clearer:



Spring configuration

root-context.xml

db-context.xml

Service implementation
This class is responsible of retrieving the data from a mongoDB database:


Controller implementation
This controller will handle requests and interact with the service in order to retrieve series data:


Integration testing
These integration tests will test our controller within a mock Spring MVC environment. In this way, we will be able to also test the mappings of our handler methods. For this purpose, the MockMvc class becomes very useful. If you want to learn how to write tests of Spring MVC controllers I highly recommend the Spring MVC Test Tutorial series by Petri Kainulainen.


I'm showing some of the tests implemented. Check SeriesIntegrationTesting for complete implementation.

Functional testing
The application contains some functional testing by using the RestTemplate class. You need the webapp deployed in order to test this.


That's all, the web application is tested and running. Now is time to migrate to Spring 4.


3   Migrating to Spring 4


Check this page to read information about migrating from earlier versions of the Spring framework

3.1   Changing maven dependencies


This section explains which dependencies should be modified. You can take a look at the complete pom.xml here.

The first step is to change Spring dependencies version from 3.2.3.RELEASE to 4.0.0.RELEASE:


The next step is to update to Servlet 3.0 specification. This step is important since some of the Spring features are based on Servlet 3.0 and won't be available. In fact, trying to execute SeriesIntegrationTesting will result in a ClassNotFoundException due to this reason, which is also explained here.


3.2   Updating of Spring namespace


Don't forget to change the namespace of your spring configuration files:

Review the information page linked in section 2 since there are some changes regarding mvc namespace.


3.3   Deprecation of jackson libraries


If you check SeriesFunctionalTesting (setup method) again you will notice that the Jackson converter is now deprecated. If you try to run the test it will throw a NoSuchMethodError due to method change in Jackson libraries:

java.lang.NoSuchMethodError: org.codehaus.jackson.map.ObjectMapper.getTypeFactory()Lorg/codehaus/jackson/map/type/TypeFactory

In Spring 4, support to Jackson 1.x has been deprecated in favor of Jackson v2. Let's change the old dependency:


For these:

Finally, if you are explicitly registering message converters you will need to change the deprecated class for the new version:


3.4   Migration complete


The migration is done. Now you can run the application and execute its tests. The next section will review some of the improvements I mentioned at the beginning of this post.


4 Spring 4 Web improvements


4.1 @ResponseBody and @RestController


If your REST API serves content in JSON or XML format, some of the API methods (annotated with @RequestMapping) will have its return type annotated with @ResponseBody. With this annotation present, the return type will be included into the response body. In Spring 4 we can simplify this in two ways:

Annotate the controller with @ResponseBody
This annotation can now be added on type level. In this way, the annotation is inherited and we are not forced to put this annotation in every method.


Annotate the controller with @RestController


This annotation simplifies the controller even more. If we check this annotation we will see that it is itself annotated with @Controller and @ResponseBody:

Including this annotation won't affect methods annotated with @ResponseEntity. The handler adapter looks up into a list of return value handlers in order to resolve who is capable of handling the response. The handler responsible of handling the ResponseEntity return type is asked before the ResponseBody type, so it will be used if ResponseEntity annotation is present at the method.


4.2 Asynchronous calls


Using the utility class RestTemplate for calling a RESTful service will block the thread until it receives a response. Spring 4 includes AsyncRestTemplate in order to execute asynchronous calls. Now you can make the call, continue doing other calculations and retrieve the response later.


Asynchronous calls with callback
Although the previous example makes an asynchronous call, the thread will block if we try to retrieve the response with futureEntity.get() if the response hasn't already been sent.
AsyncRestTemplate returns ListenableFuture, which extends Future and allows us to register a callback. The following example makes an asynchronous call and keeps going with its own tasks. When the service returns a response, it will be handled by the callback:



5 Conclusion


We took a Spring 3.2.x web application and migrated it to the new release of Spring 4.0.0. We also reviewed some of the improvements that can be applied to a Spring 4 web application.

I'm publishing my new posts on Google plus and Twitter. Follow me if you want to be updated with new content.

16 comments:

  1. Thanks for sharing such a great posts with a unique style!
    Highly appreciate your efforts

    ReplyDelete
    Replies
    1. I'm glad to see you find my post useful. Thank you for your kind words!

      Delete
  2. Thank you for a good and clean tutorial

    ReplyDelete
  3. Hi i have 2 questions:
    1. When is the rest call being made. Shouldnt the callback be set before getforobject?
    2. How many threads will be allocated if for example we make 100 async calls? 101 or 2?
    In other words, is there one thread waiting per call or you can set one thread to be allocated for waiting 100 calls?

    ReplyDelete
    Replies
    1. No, the rest call is done when the getForObject operation is invoked. This will return the result wrapped into a Future or a specialization like ListenableFuture. The last one accepts then the configuration of callbacks.

      Regarding your other question, the default constructor of AsyncRestTemplate uses a SimpleAsyncTaskExecutor. This implementation uses a new thread for each task, so in your example it would use 101 threads. However, you can pass another implementation of AsyncTaskExecutor to the overloaded constructor of AsyncRestTemplate.

      Delete
  4. Great article, I am about to do the same migration. Nice to check out this first and thanks a lot for the sharing!!

    ReplyDelete
    Replies
    1. Thank you, I hope it helps you with your task :)

      Delete
  5. Thanks for the interesting article.
    I have a problem both with spring-rest-api-v4 and spring-rest-api-v32:
    http://localhost:8080/spring-rest-api-v4/series -- HTTP 404
    It has this mapping to "/series", why is it 404?
    I did not install MongoDB, I expected it to return HTTP 500, that is the "/series" page would be called.
    What am I doing wrong?

    ReplyDelete
    Replies
    1. Hi Dmitry,

      You are forgetting the url pattern for the spring servlet mapping, which is "/spring/*". The full URL would be: http://localhost:8080/spring-rest-api-v4/spring/series.

      As you say, once you put the correct URL, you should get a 500 error since MongoDB is not running.

      Delete
    2. Thank you! Now I see my HTTP 500.

      Delete
  6. "Including this annotation won't affect methods annotated with @ResponseEntity."
    where did you found such annotation?

    ReplyDelete
    Replies
    1. Do you mean @RestController? It's included since Spring 4. See the javadoc:

      http://docs.spring.io/spring/docs/4.0.0.RELEASE/javadoc-api/org/springframework/web/bind/annotation/RestController.html

      Delete
  7. Thanks. Your post reminded me to update the 3 namespace declarations.

    ReplyDelete