Sunday, 3 November 2013

Even easier JAX-RS for Java EE7

Introduction

About a year ago, I started with my project StatelessPrime where the Java EE is the universal backend system for a lot of web technologies.  See also this blog post for more information about the ideas behind the project.
In that year, I did a lot of experimenting to check some ideas and also a lot of work is done in bringing the JSF and PrimeFaces experience to other technologies like HTML5.
In that same timeframe, Java EE 7 was launched which gave us easier ways to achieve the ideas expressed in the StatelessPrime announcement blog.
This is the first blog to give an overview of my first year of work.

JAX-RS 2.0

With the release of Java EE 7 system, there is also a new version of the JAX-RS framework. And it has the new concept of interceptors and filters.
There is the ContainerResponseFilter interface to define a filter just before the response is marshalled to the client. This is a very handy extension point in many ways:
  1. You can wrap the response in some generic response object that contains next to the data also some other information like messages, security keys and so on.
  2. It also removes the need to annotate the POJO’s that you like to send, in a marshalled form, to the client.
I can understand that you foresee the possibility to configure the way how the marshalling will be performed. But if you only want some standard behaviour, marshalling al the fields with their default options, why do you need some annotations?  It is the perfect example for convention over configuration principle.
So assume we have the following code:
@Path("registration")
public class RegistrationController {

    @GET
    @Produces({MediaType.APPLICATION_JSON})
    @Path("/all")
    public Person getList() {
        return new Person("Rudy");
    }

    private class Person {
        private String name;

        private Person(String someName) {
            name = someName;
        }

        public String getName() {
            return name;
        }

    }
}

This fails because the Person class isn’t annotated with @XmlRootElement. This is another confusing thing, I need it to annotate it with some JAXB annotation to get JSON output.

ContainerResponseFilter

But with the ContainerResponseFilter in combination with Jackson, there is an elegant solution. When you define a response filter as this, the objects returned by your methods are converted to strings (containing JSON) which are recognized without annotations.
@Provider
public class WrapPayloadFilter implements ContainerResponseFilter {
    @Override
    public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {

        Object entity = responseContext.getEntity();
        ObjectMapper mapper = new ObjectMapper();
        String payload = mapper.writeValueAsString(entity);

        responseContext.setEntity(payload);
    }
}

In another post I’ll explain another usecase for this filter.

Configuration

But the convention over configuration principle allows you to make some configuration in case you need it. The above described solution allows this also.

Suppose the Person object you want to marshal has also a date field, like his birthday.  Dates are one of those field types you like to configure the string representation of.  By using the JsonFormat annotation from Jackson, we are able to specify the format of the date representation.
        @JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd,HH:00", timezone="CET")
        private Date date ;

Conclusion

Although it is already very easy to create some JAX-RS endpoint to provide the data in JSON format to your application, it can even more simple since we now have the ContainerResponseFilter in Java EE 7 / JAX-RS 2.0.

As a first example, I demonstrated how you no longer need to annotate the POJOs which you are returning. But the ContainerResponseFilter will show his best features in the next post where we will wrap the response in another object.

The next post will be on the JSF Corner blog as I will present you an extension to the JsfMessage DeltaSpike feature which you can use in JSF and Rest environments.

1 comment:

  1. Thank you for this info. Great job with angular prime.

    ReplyDelete