Pages

Friday, 6 February 2015

Performing GZIP compression in JAXRS 2.0 services using Interceptors

Usecase:

This blogpost talks about using GZip compression on a REST service through the use of JAXRS 2.0 interceptors. The usecase below uses Jersey 2.x. Details on interceptors and filters can be found here.

Pre-requisites:

JDeveloper 12.1.3.0.0

Steps:
Use a working REST service that you already have and want to use GZip compression on. Alternately, create a REST service from scratch using the steps mentioned in my previous blogpost. However, ensure that you are using Jersey 2.0 libraries.

Next, create a new java class that implements ‘WriterInterceptor’. Write the below code in it. Notice that we have an annotation @ Provider at the class level.
We are also checking if the client accepts encoding of 'gzip' format, and only then performing the gzip compression.
  1. package project1;
    
    import java.io.IOException;
    import java.io.OutputStream;
    import java.util.zip.GZIPOutputStream;
    import javax.ws.rs.WebApplicationException;
    import javax.ws.rs.core.Context;
    import javax.ws.rs.core.HttpHeaders;
    import javax.ws.rs.ext.Provider;
    import javax.ws.rs.ext.WriterInterceptor;
    import javax.ws.rs.ext.WriterInterceptorContext;
    
    @Provider
    public class GZIPWriterInterceptor implements WriterInterceptor {
        public GZIPWriterInterceptor() {
            super();
        }
        private HttpHeaders context;
    
        public GZIPWriterInterceptor(@Context HttpHeaders context) {
            this.context = context;
        }
    
        @Override
        public void aroundWriteTo(WriterInterceptorContext writerInterceptorContext) throws IOException,WebApplicationException {
            // TODO Implement this method
            String acceptEncoding = context.getHeaderString("Accept-Encoding");
            if (acceptEncoding != null && acceptEncoding.contains("gzip")) {
                final OutputStream outputStream = writerInterceptorContext.getOutputStream();
                writerInterceptorContext.setOutputStream(new GZIPOutputStream(outputStream));
                writerInterceptorContext.getHeaders().putSingle("Content-Encoding", "gzip");
            }
            writerInterceptorContext.proceed();
    
        }
    }
Run the service class. Click on the target URL to open the HTTP analyzer and send request. Since, we have not defined the 'Accept-Encoding' header, the compression will not occur. A normal request- response cycle happens as below:



Next, add the header 'Accept-Encoding' to the request and send again. This time, gzip compression takes place. Notice that the size of data has now reduced to 123 from 155.



Find my sample application here.
Side note: The sample application also uses the concept of name binding by creating a custom annotation @Compressor and attaching it to the GZipWriterInterceptor class. Additionally, the annotation is specified on the methods for which GZip compression is required. This is not required, but comes in handy if you want to apply compression on some methods, and leave out the rest uncompressed.

Do check my next post which talks about decoding the gzip encoded data in a java client.

1 comment:

  1. Hi can you tell me how to add reader interceptor to accept the gzip compressed json from the client? i am using netbeans , can you help me?

    ReplyDelete