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.
 

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

JPA Mini Book

Learn how to leverage the power of JPA in order to create robust and flexible Java applications. With this Mini Book, you will get introduced to JPA and smoothly transition to more advanced concepts.

JVM Troubleshooting Guide

The Java virtual machine is really the foundation of any Java EE platform. Learn how to master it with this advanced guide!

Given email address is already subscribed, thank you!
Oops. Something went wrong. Please try again later.
Please provide a valid email address.
Thank you, your sign-up request was successful! Please check your e-mail inbox.
Please complete the CAPTCHA.
Please fill in the required fields.

Leave a Reply


5 × six =



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy | Contact
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.
Do you want to know how to develop your skillset and become a ...
Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

Get ready to Rock!
You can download the complementary eBooks using the links below:
Close