user3573403 user3573403 - 3 months ago 11
JSON Question

Intercept JAX-RS web service request to add JSON field

I have a JAX-RS web service that returns a takes JSON request parameters (which map to Parameter object) as shown below (it is running in WebLogic 12.2.1). Is it possible to write an interceptor or filter, such that when the web service is called, it will add an extra field in the JSON request message, so that the below method will get that extra field in the requestParameters?

@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Path("LogIn")
public Response logIn(@Context HttpServletRequest request, Parameters requestParameters) {...}


Thanks!

Answer

Interceptors

It could be achieved with an interceptor.

Interceptors are intended to manipulate entities, via manipulating entity input/output streams. There are two kinds of interceptors, ReaderInterceptor and WriterInterceptor.

Reader interceptors are used to manipulate inbound entity streams. These are the streams coming from the "wire". So, using a reader interceptor you can manipulate request entity stream on the server side. Writer interceptors are used for cases where entity is written to the "wire" which on the server means when writing out a response entity

The following interceptor, which implements the ReaderInterceptor interface, allows you to modify the requested entity on server side:

@Provider
public class CustomReaderInterceptor implements ReaderInterceptor {

    @Override
    public Object aroundReadFrom(ReaderInterceptorContext context) 
                      throws IOException, WebApplicationException {

        InputStream stream = context.getInputStream();

        // Manipulate the HTTP entity using the InputStream

        context.setInputStream(stream);
        return context.proceed();
    }
}

Please note the above interceptor is global, that is, it will be executed for all resource methods.

When using Jackson, your ReaderInterceptor#aroundReadFrom(ReaderInterceptorContext) method implementation could be like:

// Create a Jackson ObjectMapper instance (it can be injected instead)
ObjectMapper mapper = new ObjectMapper();

// Parse the requested entity into a JSON tree
JsonNode tree = mapper.readTree(context.getInputStream());

// Add a property to the JSON
((ObjectNode) tree).put("field", "value");

// Set the input stream containing the manipulated JSON
context.setInputStream(new ByteArrayInputStream(mapper.writeValueAsBytes(tree)));

// Proceed to the next interceptor in the chain
context.proceed();

Name binding

To execute the interceptor for only some hand-picked resources methods, you can used name binding.

Name binding is a concept that allows to say to a JAX-RS runtime that a specific filter or interceptor will be executed only for a specific resource method. When a filter or an interceptor is limited only to a specific resource method we say that it is name-bound.

Filters can be assigned to a resource method using the @NameBinding annotation. The annotation is used as meta annotation for other user implemented annotations that are applied to a providers and resource methods.

A name binding annotation can be defined as following (the name of the annotation is up to you):

@NameBinding
@Retention(RUNTIME)
@Target({TYPE, METHOD})
public @interface CustomizeResponse { }

Place the above defined annotation on your interceptor class:

@Provider
@CustomizeResponse
public class CustomReaderInterceptor implements ReaderInterceptor {
    ...
}

To assign the interceptor to a resource method, place the above defined annotation on the resource method:

@GET
@CustomizeResponse
@Produces(MediaType.APPLICATION_JSON)
public Response myMethod() {
    ...
}

Name binding can be applied on resource classes as well. It means the interceptor will be executed for all resource methods of that resource class:

@Path("/foo")
@CustomizeResponse
public class MyResource() {
    ...
}

Note that global filters and interceptor are always executed, so even for resource methods which have any name binding annotations.

Additional resources

For more details on interceptors, have a look at Jersey documentation.