JAX-RS ChunkedOutput and ChunkedInput Example
In Jersey you can use ChunkedOutput
to send response to a client in chunks. By using a chunked output the jersey runtime is informed that the response will be chunked and that the processing works asynchronously in a non-blocking fashion.
ChunkedOutput
In the following example we return a ChunkedOutput
instance. This informs Jersey that the response will be asynchronously processed. Usually, a long running method will be executed and as soon the method returns, the response will be sent to the client.
package com.memorynotfound.jaxrs.chunked;
import org.glassfish.jersey.server.ChunkedOutput;
import javax.ws.rs.*;
import java.io.*;
@Path("/numbers")
public class NumbersResource {
@GET
public ChunkedOutput<String> streamExample(){
final ChunkedOutput<String> output = new ChunkedOutput<String>(String.class);
new Thread() {
@Override
public void run() {
try {
for (int i = 0; i < 100000 ; i++){
output.write(i + " ");
}
} catch (IOException e){
e.printStackTrace();
} finally {
try {
output.close();
} catch (IOException e){
e.printStackTrace();
}
}
}
}.start();
return output;
}
}
ChunkedInput
On the client side, we use the ChunkedInput
to receive chunked messages. The following example shows how to read from ChunkedInput
.
package com.memorynotfound.jaxrs.chunked;
import org.glassfish.jersey.client.ChunkedInput;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.Response;
public class RunClient {
public static void main(String... args){
Client client = ClientBuilder.newClient();
Response response = client
.target("http://localhost:8081/jaxrs-chuncked/api")
.path("numbers")
.request()
.get();
ChunkedInput<String> input = response.readEntity(new GenericType<ChunkedInput<String>>() {});
String chunk;
while ((chunk = input.read()) != null){
System.out.println("chunk: " + chunk);
}
}
}
I’ve had issues with ChunkedOutput not being fully thread safe even though flushQueue() has some synchronization. What can happen is that the thread returning the ChunkedOutput class to the server can attempt to read and flush the queue at the same time as the thread performing the work to write the chunks, writes and flushes the queue. The result is that one of the threads assumes it should close the stream an subsequent writes fail with an EOF exception. In order to overcome this issue I needed to derive a class and override the offending functions. import java.lang.reflect.Type; import javax.ws.rs.container.ConnectionCallback;… Read more »