1

I'm sending a lots of data as a JSON response in JAX-RS endpoint.

Is there any way to set "always-compress" parameter in javax.ws.rs as annotation to the endpoint or on payara-micro level as parameter, to always compress the response?

The current state is that the endpoint supports both uncompressed and compressed (e.g.curl --compressed) way of providing the data.

@GET
@Path("/big-response")
@Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "Provides Json information about some etities")
@ApiResponses(value = {
        @ApiResponse(code = 200, message = "Transfer successful"),
        @ApiResponse(code = 400, message = "Bad request"),
        @ApiResponse(code = 500, message = "Internal server error")})
public void retrieveTheData() {

I want, that the endpoint will be always responding with compressed data (content-encoding: gzip).

wbrycki
  • 121
  • 1
  • 8
  • If the compression could be applied to the every JAX-RS endpoint separately as the annotation, it would be even better. Thank you for any suggestions. – wbrycki May 28 '19 at 10:52
  • There is a similar problem on that page:https://stackoverflow.com/questions/19765582/how-to-make-jersey-use-gzip-compression-for-the-response-message-body but not sure if enforces the compression. – wbrycki May 28 '19 at 11:26
  • There is also a way with implementing a WriterInterceptor here: https://www.codepedia.org/ama/how-to-compress-responses-in-java-rest-api-with-gzip-and-jersey/ and use a @Compress annotation -> this could be a possible solution – wbrycki May 28 '19 at 14:24

1 Answers1

2
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

import javax.ws.rs.NameBinding;

//@Compress annotation is the name binding annotation
@NameBinding
@Retention(RetentionPolicy.RUNTIME)
public @interface Compress {
}

Interceptor

import java.io.IOException;
import java.io.OutputStream;
import java.util.zip.Deflater;
import java.util.zip.GZIPOutputStream;

import javax.enterprise.context.Dependent;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.Provider;
import javax.ws.rs.ext.WriterInterceptor;
import javax.ws.rs.ext.WriterInterceptorContext;

import hr.abc.leonus.api.gateway.util.Compress;

@Provider
@Compress
public class GZIPWriterInterceptor implements WriterInterceptor {

    public static final String CONTENT_ENCODING = "Content-Encoding";
    public static final String GZIP = "gzip";

    @Override
    public void aroundWriteTo(WriterInterceptorContext context)
            throws IOException, WebApplicationException {

        MultivaluedMap<String, Object> headers = context.getHeaders();
        headers.add(CONTENT_ENCODING, GZIP);

        final OutputStream outputStream = context.getOutputStream();

        GatewayGZIPOutputStream gzipStream = new GatewayGZIPOutputStream(outputStream);
        gzipStream.setLevel(Deflater.BEST_SPEED);
        context.setOutputStream(gzipStream);
        context.proceed();
    }
}

class GatewayGZIPOutputStreamextends GZIPOutputStream {

    public GatewayGZIPOutputStream(OutputStream out) throws IOException {
        super(out);
    }

    public void setLevel(int level) {
        def.setLevel(level);
    }
}

Usage on the endpoint

@Compress
@GET
@Path("/big-response")
@Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "Provides Json information about some etities")
@ApiResponses(value = {
        @ApiResponse(code = 200, message = "Transfer successful"),
        @ApiResponse(code = 400, message = "Bad request"),
        @ApiResponse(code = 500, message = "Internal server error")})
public void retrieveTheData() {
}

You can adjust compression level in GatewayGZIPOutputStreamobject by seting the level . I'am using minimum for best speed. @Compress annotation can be used on method or on the resource class for every method inside the class.

Igor Vuković
  • 742
  • 12
  • 25
  • I've tried this and it seems the `WriterInterceptor` isn't called at all. If I use [this "short version"](https://www.codepedia.org/ama/how-to-compress-responses-in-java-rest-api-with-gzip-and-jersey/) it works, but applies to all endpoints. I can't get it to only apply to certain endpoints like shown in your answer. Any ideas? – Baz Oct 27 '22 at 09:09
  • 1
    Never mind, it was caused by a mix of `javax` and `jakarta` imports :/ Once I switched them all to `jakarta` it worked fine. – Baz Oct 27 '22 at 09:34