Consuming Spring-hateoas Rest service using Spring RestTemplate and Super type tokens

Spring-hateoas provides an excellent way for applications to create REST based services which follow the HATEOAS principle.

My objective here is not to show how to create the service itself, but to demonstrate how to write a client to the service.

The sample service that I am going to use is the ” the-spring-rest-stack” written by Josh Long( @starbuxman). The specific subproject that I am going to use is the hateoas one here. If this subproject is run using “mvn jetty” command, a REST based endpoint to list the details of a user is available at http://localhost:8080/users/2 where “2″ is the id of the user and gives a result of the following structure:

{
    "links": [{
        "rel": "self",
        "href": "http://localhost:8080/users/2"
    }, {
        "rel": "customers",
        "href": "http://localhost:8080/users/2/customers"
    }, {
        "rel": "photo",
        "href": "http://localhost:8080/users/2/photo"
    }],
    "id": 2,
    "firstName": "Lois",
    "profilePhotoMediaType": null,
    "lastName": "Lane",
    "username": "loislane",
    "password": null,
    "profilePhotoImported": false,
    "enabled": true,
    "signupDate": 1370201631000
}

To get to a specific customer of this user, the endpoint is at http://localhost:8080/users/2/customers/17, which gives an output of the following structure:

{
    "links": [{
        "rel": "self",
        "href": "http://localhost:8080/users/2/customers/17"
    }, {
        "rel": "user",
        "href": "http://localhost:8080/users/2"
    }],
    "id": 17,
    "signupDate": 1372461079000,
    "firstName": "Scott",
    "lastName": "Andrews",
    "databaseId": 17
}

Now for a consumer of these two services, the result can be represented by a java type called Resource in the Spring-hateoas project and is a generic class with the following signature:

public class Resource<T> extends ResourceSupport {

 protected Resource() {
  this.content = null;
 }

 public Resource(T content, Link... links) {
  this(content, Arrays.asList(links));
 }

...

So the consumer of the above two services will get back the following two types:

Resource<User> user = .... //call to the service

Resource<Customer> customer = ... //call to the service

The issue now is that since the “user” and “customer” above are parameterized types, if I were to bind the types using Jackson as the json processor, I would be doing something along the following lines:

ObjectMapper objectMapper = new ObjectMapper();
Resource<Customer> customer = objectMapper.readValue(customerAsJson, Resource.class);
Resource<User> user = objectMapper.readValue(userAsJson, Resource.class);

The above will not work however, the reason is because of the lost type information of the parameterized Resource due to Java type erasure, Jackson wouldn’t know to create an instance of Resource<User> or Resource<Customer>

The fix is to use a Super Type Token, which is essentially a way to provide the type information for libraries like Jackson and I have blogged about it before here. With this, a working code to map the json to the appropriate parameterized type would look like this:

ObjectMapper objectMapper = new ObjectMapper();
Resource<Customer> customer = objectMapper.readValue(customerAsJson, new TypeReference<Resource<Customer>>() {});
Resource<User> customer = objectMapper.readValue(userAsJson, new TypeReference<Resource<User>>() {});

Spring’s client abstraction to deal with Rest based services is RestTemplate, and this can deal with a variety of message formats(xml, json, atom etc) using an abstraction called HttpMessageConverter to deal with the specifics of binding for each of the message formats.

Spring RestTemplate provides its own implementation of Super Type token to be able to bind different message formats to parameterized types, along the lines of Jackson’s TypeReference, it is called the ParameterizedTypeReference.

ParameterizedTypeReference can be used to cleanly bind Rest responses for User and Customer to Java types this way:

RestTemplate restTemplate = new RestTemplate();
ResponseEntity<Resource<User>> responseEntity =
  restTemplate.exchange("http://localhost:8080/users/2", HttpMethod.GET, null, new ParameterizedTypeReference<Resource<User>>() {}, Collections.emptyMap());
if (responseEntity.getStatusCode() == HttpStatus.OK) {
 Resource<User> userResource = responseEntity.getBody();
 User user = userResource.getContent();
}
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<Resource<Customer>> responseEntity =
  restTemplate.exchange("http://localhost:8080/users/2/customers/17", HttpMethod.GET, null, new ParameterizedTypeReference<Resource<Customer>>() {}, Collections.emptyMap());
if (responseEntity.getStatusCode() == HttpStatus.OK) {
 Resource<Customer> customerResource = responseEntity.getBody();
 Customer customer = customerResource.getContent();
}

In conclusion, ParameterizedTypeReference provides a neat way of dealing with the parameterized types and is incredibly useful in consuming the Spring Hateoas based REST services.
 

Related Whitepaper:

Functional Programming in Java: Harnessing the Power of Java 8 Lambda Expressions

Get ready to program in a whole new way!

Functional Programming in Java will help you quickly get on top of the new, essential Java 8 language features and the functional style that will change and improve your code. This short, targeted book will help you make the paradigm shift from the old imperative way to a less error-prone, more elegant, and concise coding style that’s also a breeze to parallelize. You’ll explore the syntax and semantics of lambda expressions, method and constructor references, and functional interfaces. You’ll design and write applications better using the new standards in Java 8 and the JDK.

Get it Now!  

Leave a Reply


× 7 = sixty three



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.

Sign up for our Newsletter

15,153 insiders are already enjoying weekly updates and complimentary whitepapers! Join them now to gain exclusive access to the latest news in the Java world, as well as insights about Android, Scala, Groovy and other related technologies.

As an extra bonus, by joining you will get our brand new e-books, published by Java Code Geeks and their JCG partners for your reading pleasure! Enter your info and stay on top of things,

  • Fresh trends
  • Cases and examples
  • Research and insights
  • Two complimentary e-books