users@jersey.java.net

[Jersey] Cannot set new entity stream in request filter

From: Michael Pratt <prattm_at_gmail.com>
Date: Wed, 24 Sep 2014 09:24:02 -0600

I'm using Jersey 2.12 and need to examine the request entity when it's
form-url-encoded. In Jersey 1 I could simply call request.getFormdata() but
that method is gone in Jersey 2. So I'm trying to write a filter that grabs
the entity stream as a Form object and then replaces the entity stream with
a new stream, but the stream is never re-marked as open and causes
IllegalStateExceptions. Here is my filter, which is exactly based on the
Jersey 1 impl:

@Provider
public class FormDataFilter implements ContainerRequestFilter
{
  @Override
  public void filter(ContainerRequestContext requestContext)
  throws IOException
  {
    if (requestContext.hasEntity() &&
MediaTypes.typeEqual(MediaType.APPLICATION_FORM_URLENCODED_TYPE,
request.getMediaType()))
    {
       InputStream in = request.getEntityStream();
       if (in.getClass() != ByteArrayInputStream.class) {
         // Buffer input
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         try {
           ReaderWriter.writeTo(in, baos);
         } catch (IOException e) {
           throw new IllegalArgumentException(e);
         }

         in = new ByteArrayInputStream(baos.toByteArray());
         request.setEntityStream(in);
       }

       ByteArrayInputStream bais = (ByteArrayInputStream) in;
       Form f = request.readEntity(Form.class);
       bais.reset();
    }
  }
}

The problem is once request.readyEntity() is called, the entityContent is
marked as closed, so the next filter or resource to try and consume the
entity throws an IllegalStateException. I have tried re-arranging the order
of readEntity() and setEntityStream() with no luck.

What is the proper way to do this? I need to do this in a request filter
because I need to set properties on the request context that are later used
by one of my response filters.

Thanks,
Mike