2

I'm using Dropwizard 0.9.1 in my application and I have a GET-Method returning a ChunkedOuput like described here. MediaType should be APPLICATION_JSON and it works but the result is not a valid JSON.

Here is the example Ressource:

@GET
@Path("/chunktest")
@Produces(MediaType.APPLICATION_JSON)
public class AsyncResource {
    @GET
    public ChunkedOutput<MyCustomObject> getChunkedResponse() {
        final ChunkedOutput<MyCustomObject> output = new ChunkedOutput<MyCustomObject>(MyCustomObject.class);

        new Thread() {
            public void run() {
                try {
                    MyCustomObject chunk;

                    while ((chunk = getNextCustomObject()) != null) {
                        output.write(chunk);
                    }
                } catch (IOException e) {
                    // IOException thrown when writing the
                    // chunks of response: should be handled
                } finally {
                    output.close();
                        // simplified: IOException thrown from
                        // this close() should be handled here...
                }
            }
        }.start();

        // the output will be probably returned even before
        // a first chunk is written by the new thread
        return output;
    }

    private MyCustomObjectgetNextCustomObject() {
        // ... long running operation that returns
        //     next object or null
    }
}

Now if I try curl this non-valid JSON is returned:

HTTP/1.1 200 OK
Date: Thu, 19 Nov 2015 13:08:28 GMT
Content-Type: application/json
Vary: Accept-Encoding
Transfer-Encoding: chunked

{
   "key1" : "value1a",
   "key2" : "value2a"
}{
   "key1" : "value1b",
   "key2" : "value2b"
}{
   "key1" : "value1c",
   "key2" : "value2c"
}{
   "key1" : "value1d",
   "key2" : "value2d"
}

I also tried to use a chunk delimiter but with this I can only fix the "," between the chunk-JSON's, but I have no idea how to insert the start/end brackets

{

and

}

Does anyone know how to fix this?

heaphach
  • 1,492
  • 1
  • 20
  • 44
  • Couldn't you just do `output.write("[")` to the start of the `run()` method, and `output.write("]")` to the finally block? That, combined with the delimiter that you mentioned above, would turn the output into a JSON array. – MusikPolice Dec 15 '15 at 20:15
  • Using a messageBodyWriter with stuff mentioned above is actual the only way, how I can make this working, but it is still just a workaround for me ;-) – heaphach Dec 16 '15 at 08:09
  • @MusikPolice How would that be done? The ChunkedOutput is typed to other than String.class... – Oskar Lund Sep 14 '17 at 17:12

2 Answers2

2

Hacked this together :)

public class ChunkedOutputJson<T> extends ChunkedOutput<String> {
    private boolean isFirstChunk = true;
    private final JsonSerializer jsonSerializer;
    public ChunkedOutputJson(JsonSerializer jsonSerializer) {
        super(String.class);
        this.jsonSerializer = jsonSerializer;
    }
    public void writeChunk(T chunk) throws IOException {
        if (isFirstChunk) {
            super.write("[\n");
            isFirstChunk = false;
        } else {
            super.write(",\n");
        }
        super.write(jsonSerializer.toJson(chunk));
    }
    @Override
    public void close() throws IOException {
        super.write("\n]\n");
        super.close();
    }
}

Reason I'm not using the delimiter property in the original ChunkedOutput is that it will add it also after the last element and hence screw up the json format (if you need it strict).

Oskar Lund
  • 339
  • 2
  • 11
-1

How about new ChunkedOutput<MyCustomObject>(MyCustomObject.class, ",")?

Javadoc for the 2nd parameter:

@param chunkDelimiter custom chunk delimiter string. Must not be {code null}.

(For Jersey 2)

fwonce
  • 397
  • 1
  • 5
  • 18