Using an Interceptor in Jersey I can manipulate the Output, however, I also want to add a Header to the response which value is calculated from the result of the output.
@Sha256Sum
public class Sha256SumInterceptor implements WriterInterceptor {
public static final String SHA256_HASH_HEADER_NAME = "SHA256-SUM";
@Override
public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException {
// Retrieve the OutputStream, read the contents and calculate the hashsum.
// Set the header value in context.
context.proceed();
}
}
However, the issue is that when I finally have read the entire stream, I'm unable to set the headers as when context.proceed is called and the contents written (and thus enabling me to do anything with it) I can no longer set the header.
My question in short: How do I capture the entire stream output as a byte[], calculate a result from the array of bytes and finally set the header in the response to the computed result? I do not want to deplete the output stream.
If you've ever worked with an AOP framework or even CDI interceptors, you'll have worked with the concept of Around-Advice or Around-Invoke, respectively. You can perform operations before and after the invocation of the advised/intercepted method. context.proceed()
works the same way; it's the method invocation (or more precisely the MessageBodyWriter
doing it's writing). We can perform some operations before the MessageBodyWriter
does it's job, call proceed()
to let the writer do it's work, then we can do some more work.
With that said, here are the steps you can take:
OutputStream
from the context
, with context.getOutputStream()
ByteArrayOutputStream
and set that as the OutputStream
on the context, with context.setOutputStream(baos)
context.proceed()
. What this does is have the MessageBodyWriter
write to the ByteArrayOutputStream
.byte[]
from the ByteArrayOutputStream
with baos.toByteArray()
byte[]
and set the headerbyte[]
to the old OutputStream
.OutputStream
on the context
to the old OutputStream
.Here's the basic implementation (tested and works as expected)
@Provider
public class ChecksumInterceptor implements WriterInterceptor {
@Override
public void aroundWriteTo(WriterInterceptorContext context)
throws IOException, WebApplicationException {
OutputStream old = context.getOutputStream();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
try {
context.setOutputStream(buffer);
// let MessageBodyWriter do it's job
context.proceed();
// get bytes
byte[] entity = buffer.toByteArray();
String checksum = ChecksumUtil.createChecksum(entity);
context.getHeaders().putSingle("X-Checksum", checksum);
old.write(entity);
} finally {
context.setOutputStream(old);
}
}
}