Reputation: 1812
I have a web service method as follow (deployed on WebLogic 12.2.1), which I can receive the JSON request body in the POJO object "requestParameters":
@POST
@SessionChecker
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Path("LogIn")
public Response logIn(@Context HttpServletRequest request, Parameters requestParameters) {
....
}
I have a filter that I want to intercept the request before the above web service method is called.
@Provider
@SessionChecker
public class CheckSessionFilter implements ContainerRequestFilter {
@Context
private HttpServletRequest servletRequest;
@Override
public void filter(ContainerRequestContext requestContext) throws WebApplicationException {
....
}
}
In the filter() method, how do I get the JSON message body into the POJO object of type Parameters? I just need to get one attribute from the JSON message. After the filter is done, the JSON message should pass on to the web service method without change.
Thanks in advance.
Upvotes: 1
Views: 3427
Reputation: 209004
Here's the problem. When your filter is hit, the request stream (InputStream
) hasn't been read yet. So if you try to read it, then Jersey will not be able to read it, as a stream can only be read once, so it will be empty.
Jersey actually offers a solution to this. The ContainerRequestContext
, is actually an instance of Jersey specific ContainerRequest
. If you look at the linked API, you will find a bufferEntity()
method. This allows us to read the entity, and Jersey will be able to read it again. So your first step is to make that call
@Override
public void filter(ContainerRequestContext requestContext)
ContainerRequest cr = (ContainerRequest) requestContext;
cr.bufferEntity();
}
Now you can get the entity. If you look at the API for ContainerRequest
, there are also methods to readEntity(..)
. If you are familiar with the JAX-RS Client API, you may have before used Response#readEntity(...class)
to read the response entity. The ContainerRequest#readEntity(..)
works pretty much the same way.
So if you know what the JSON format is supposed to be, and you have the POJO, you could do
POJO pojo = cr.readEntity(POJO.class);
Otherwise, if the format will change from request to request, you could extract the data as a map
Map<String, Object> json = cr.readEntity(new GenericType<Map<String, Object>>(){});
If you are using one JAX-RS APIs, and not Jersey specific APIs, then the above is not doable. You will instead need to read the stream to get the JSON, and set the stream back, so that Jersey can read it. If might look something like
InputStream entityIn = requestContext.getEntityStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// write `entityIn` to `baos`
byte[] bytes = baos.toByteArray();
POJO pojo = new ObjectMapper().readValue(bytes, POJO.class);
// do something with POJO
requestContext.setEntityStream(new ByteArrayInputStream(bytes));
Of course you will need to some JSON deserializer to do this. I just used Jackson in the example.
It's not as elegant as the first example, but you don't have much option if you are strictly sticking the JAX-RS APIs. If you can I would suggest just adding the Jersey dependencies to your project as provided (compile-time) so that you can use the APIs, since you are using Jersey with WebLogic anyway.
Upvotes: 2