17

Clarification: this question was about GZIPping an JAX-WS-based REST service, but I've decided to change the topic to make it easier to find

I'm implementing a REST service via JAX-WS Provider <Source>, and publishing it with standard Endpoint (the reason is that I want to avoid using a servlet container or application server).

Is there a way to make server to gzip response content, if Accept-Encoding: gzip is present?


HOW-TO

Samples provided by nicore actually works, and it allows you to make JAX-RS-styled server on top of embedded lightweight server without servlet container, but there are few moments to be considered.

If you prefer to manage classes by yourself (and save a time during startup), you may use the following:

Example

JAX-RS hello world class:

@Path("/helloworld")
public class RestServer {

    @GET
    @Produces("text/html")
    public String getMessage(){
        System.out.println("sayHello()");
        return "Hello, world!";
    }
}

Main method:

For Simple Server:

public static void main(String[] args) throws Exception{
    DefaultResourceConfig resourceConfig = new DefaultResourceConfig(RestServer.class);
    // The following line is to enable GZIP when client accepts it
    resourceConfig.getContainerResponseFilters().add(new GZIPContentEncodingFilter());
    Closeable server = SimpleServerFactory.create("http://0.0.0.0:5555", resourceConfig);
    try {
        System.out.println("Press any key to stop the service...");
        System.in.read();
    } finally {
        server.close();
    }
}

For Grizzly2:

public static void main(String[] args) throws Exception{
    DefaultResourceConfig resourceConfig = new DefaultResourceConfig(RestServer.class);
    // The following line is to enable GZIP when client accepts it
    resourceConfig.getContainerResponseFilters().add(new GZIPContentEncodingFilter());
    HttpServer server = GrizzlyServerFactory.createHttpServer("http://0.0.0.0:5555" , resourceConfig);
    try {
        System.out.println("Press any key to stop the service...");
        System.in.read();
    } finally {
        server.stop();
    }
}

Resolved dependencies:

Simple:

Grizzly:

Jersey:

Notice

Make sure the javax.ws.rs archive didnt get into your classpath, as it conflicts with Jersey's implementation. The worst thing here is a silent 404 error with no logging - only a small note on FINER level is logged.

Alex Abdugafarov
  • 6,112
  • 7
  • 35
  • 59
  • Isn't that just up to the container (Tomcat, Jetty, etc.) to sort out? – Donal Fellows Nov 26 '11 at 09:59
  • We're not currently using servlet containe, and this REST service is probably the only place where we'll need it. I don't really think it's worth it to examine, set up, and tune a whole servlet container just for gzipping this little guy. So I want to avoid using one, if possible. – Alex Abdugafarov Nov 26 '11 at 10:07
  • 1
    Just for clarity, the examples are for Jersey 1.x and are not accurate for Jersey 2.x. See the documentation for the latter case: https://jersey.java.net/documentation/latest/deployment.html#deployment.http – Ophidian Jul 08 '14 at 20:26

3 Answers3

16

If you really want to do REST with Java I would suggest you to to use a JAX-RS implementation (RESTeasy, Jersey...).

If your main concern is the dependency on a servlet container, you could use the JAX-RS RuntimeDelegate to register your application as a JAX-RS endpoint.

// Using grizzly as the underlaying server
SelectorThread st = RuntimeDelegate.createEndpoint(new MyApplication(), SelectorThread.class);

st.startEndpoint();

// Wait...
st.stopEndpoint();

Concerning GZIP encoding, each JAX-RS provider has different approaches. Jersey provides a filter to accomplish the encoding transparently. RESTEasy provides an annotation for that.

EDIT

I did some small tests. The following two things will definitely work for you, assuming you are using Maven.

Using Jersey + SimpleServer:

    public static void main( String[] args ) throws Exception {

    java.io.Closeable server = null;

    try {
        // Creates a server and listens on the address below.
        // Scans classpath for JAX-RS resources
        server = SimpleServerFactory.create("http://localhost:5555");
        System.out.println("Press any key to stop the service...");
        System.in.read();
    } finally {
        try {
            if (server != null) {
                server.close();
            }
        } finally {
            ;
        }
    }
}

with maven dependencies

<dependency>
    <groupId>com.sun.jersey</groupId>
    <artifactId>jersey-core</artifactId>
    <version>1.10</version>
</dependency>
<dependency>
    <groupId>com.sun.jersey.contribs</groupId>
    <artifactId>jersey-simple-server</artifactId>
    <version>1.10</version>
</dependency>

Or using the Jersey + Grizzly2:

public static void main(String[] args) throws Exception {

    HttpServer server = null;

    try {
        server = GrizzlyServerFactory.createHttpServer("http://localhost:5555");
        System.out.println("Press any key to stop the service...");
        System.in.read();
    } finally {
        try {
            if (server != null) {
                server.stop();
            }
        } finally {
            ;
        }
    }
}

with maven dependencies

<dependency>
    <groupId>com.sun.jersey</groupId>
    <artifactId>jersey-core</artifactId>
    <version>1.10</version>
</dependency>
<dependency>
    <groupId>com.sun.jersey</groupId>
    <artifactId>jersey-grizzly2</artifactId>
    <version>1.10</version>
</dependency>

Honestly speaking I was not able to get the RuntimeDelegate sample working, too. There certainly is a way to start RESTEasy out of the box, too but I cannot recall it at the moment.

nre
  • 1,299
  • 11
  • 24
  • 3
    I'm sorry, but the JAX-RS (and especially it's `RuntimeDelegate`) is one of the most horrible and bad-designed things I ever saw. I'm struggling with both Jersey and RESTEasy for two hours and still don't get, how to make any of them work without servlet container. Could you please provide a simple example of how to implement that? P.S. And btw - which jar contains `SelectorThread`? Grizzly itself has tons of jars, while Jersey doesn't seems to contain this one. – Alex Abdugafarov Nov 26 '11 at 12:43
  • 1
    Well, I personally like JAX-RS and produced some quite cool things with it. At least it is a better option than developing everything yourself I guess. Concerning the JAR question: I cannot tell the answer because I use maven to sort that out for me. Maybe the Jersey wiki pages help. – nre Nov 26 '11 at 14:44
  • Took time to figure this out, but it work, thank you. I'll accept your answer and edit my question to clarify this for anyone else going this way. – Alex Abdugafarov Nov 29 '11 at 07:06
  • Probably adding to my necro badge here on SO but what the heck! I'm struggling to get this to work with jersey throwing an exception - "The ResourceConfig instance does not contain any root resource classes." Also I'm guessing this doesn't need a web.xml which is one of the things I tried. Using jersey-simple-server 1.17.1 – sfk Oct 23 '13 at 23:34
0

gzipping the output is the reponsibility of JAX WS implementation. You should refer to server's (Tomcat, Glassfish, JBoss, etc) documentation in order to configure your http network listeners.

andbi
  • 4,426
  • 5
  • 45
  • 70
0

If using CXF for your JAX-WS implementation (or JAX-RS), you could just add @GZIP annotation onto the service class.

Daniel Kulp
  • 14,447
  • 4
  • 45
  • 37