Friday, January 17, 2014

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.

Thursday, January 9, 2014

Spring Integration Publisher

Consider a hypothetical requirement - You have a service class in your application and you want to capture some information around the calls to this service:

@Service
public class SampleBean {
 private static final Logger logger = LoggerFactory.getLogger(SampleBean.class);

 public Response call(Request request) {
  logger.info("SampleBean.call invoked");
  return new Response(true);
 }
}

AOP is a great fit for such a requirement, it allows the information around a method call(a pointcut) to be cleanly captured and some processing(an advice) to be done with this information:

public class AuditAspect {
 private static final Logger logger = LoggerFactory.getLogger(AuditAspect.class);
 @Pointcut("execution( * core.SampleBean.call(model.Request)) && args(r)")
 public void beanCalls(Request r){}

 @Around("beanCalls(r)")
 public Object auditCalls(ProceedingJoinPoint pjp, Request r) {
     logger.info("Capturing request: " + r);
  try{
   Object response = pjp.proceed();
   logger.info("Capturing response: " + response);
   return response;
  }catch(Throwable e) {
   throw new RuntimeException(e);
  }
 }
}


This appears to be good enough. Now what if I wanted to return the response back to the client immediately but continue to process the context of the method call - well we can place the logic of Advice in a separate thread using a ThreadPool. Let me add another layer of complexity now, what if we wanted to absolutely ensure that context is not lost - a good way to do this would be to keep the context of the method call outside the JVM, typically messaging providers like RabbitMQ and ActiveMQ will fit in very well.


Considering these additional requirements, a simpler solution especially with messaging scenarios coming into play will be to use Spring Integration. Let us start by defining a new Spring Integration application context:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/integration"
    xmlns:beans="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
  http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <annotation-config/>

    <channel id="tobeprocessedlater"/>

    <logging-channel-adapter channel="tobeprocessedlater" log-full-message="true"/>

</beans:beans>

It just has the definition of a channel, and an outbound adapter which reads from this channel and logs the full message. To capture the context of the call to the SampleBean a Publisher annotation can be added to the relevant methods of SampleBean which will direct "stuff" to the channel which is added to the annotation.

@Service
public class SampleBean {
 private static final Logger logger = LoggerFactory.getLogger(SampleBean.class);

 @Publisher(channel = "tobeprocessedlater")
 public Response call(@Header("request") Request request) {
  logger.info("SampleBean.call invoked");
  return new Response(true);
 }
}

what "stuff" is sent to this "tobeprocessedlater" channel is specified through additional annotations - by default the return value from the method is sent to the channel, additionally I have tagged the request also with the @Header annotation, this will make the request to be sent in as a header to the response message. Just for completeness, the integration context has a <annotation-config/> tag, this tag registers the relevant components that look for @Publisher annotation and weave in the additional action to be performed if it finds one.

If this code is executed now, the output will be along these lines:

                       core.SampleBean - SampleBean.call invoked
o.s.integration.handler.LoggingHandler - [Payload=Response{success=true}][Headers={request=RequestType1{attr='null'}, id=52997b10-dc8e-e0eb-a82a-88c1df68fca5, timestamp=1389268390212}]

Now, to layer in the first requirement, to handle the advice(in this case the logging) in a separate thread of execution:

This can be done with just a configuration change! - instead of publishing the message to a direct channel, publish it to a channel type that can buffer messages or use an executor to dispatch messages, I have opted to use an executor channel in this example:

    <channel id="tobeprocessedlater">
        <dispatcher task-executor="taskExecutor"/>
    </channel>

Now to add the requirement to make the async message processing a little more reliable by publishing it to an external Messaging provider(and processing the messages later), let me demonstrate this by publishing the messages to RabbitMQ, the code change again is pure configuration and nothing in the code changes!:

    <channel id="tobeprocessedlater"/>

    <int-amqp:outbound-channel-adapter amqp-template="amqpTemplate" channel="tobeprocessedlater"  />

The messaging sink could have been anything - a database, a file system, ActiveMQ, and the change that would have been required is pure configuration.

Wednesday, January 1, 2014

Objenesis for class instantiation

Objenesis is a neat little library for instantiating classes . Consider the following class:

public class Person {
    private final String firstName;
    private final String lastName;

    public Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
    ...
}    

If the structure of the class and its constructor is known, then a framework can instantiate this class purely using reflection:

Constructor<Person> ctor = Person.class.getDeclaredConstructor(String.class, String.class);
Person personThroughCtor = ctor.newInstance("FirstName", "LastName");


However, if the constructor structure is not known ahead of time, creating the class instance is not easy, for eg the following will throw an exception:

Constructor<Person> ctor = Person.class.getDeclaredConstructor();
Person personThroughCtor = ctor.newInstance("FirstName", "LastName");

Exception:

java.lang.NoSuchMethodException: mvcsample.obj.Person.<init>()
 at java.lang.Class.getConstructor0(Class.java:2810)
 at java.lang.Class.getDeclaredConstructor(Class.java:2053)


Objenesis provides the solution here, of being able to instantiate an instance of Person class without needing to call its constructor:

Objenesis objenesis = new ObjenesisStd(true);
ObjectInstantiator personInstantiator = objenesis.getInstantiatorOf(Person.class);

Person person = (Person)personInstantiator.newInstance();