4

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!

user3573403
  • 1,780
  • 5
  • 38
  • 64
  • Not sure if WebLogic behaves similar to Jersey, which [offers filters and interceptor support](https://jersey.java.net/documentation/latest/filters-and-interceptors.html) – Roman Vottner Apr 11 '16 at 07:36
  • Possible duplicate of [How to apply interceptors and filters to restful services on Weblogic 12c](http://stackoverflow.com/questions/22333128/how-to-apply-interceptors-and-filters-to-restful-services-on-weblogic-12c) – Roman Vottner Apr 11 '16 at 07:37
  • I know about filters and interceptors. What I don't know is whether we can add additional JSON request parameters in the filter/interceptor. I am using Jersey with WebLogic, by the way. – user3573403 Apr 11 '16 at 07:46
  • Are you using Jackson? – cassiomolin Apr 11 '16 at 10:11
  • Yes, I use Jackson as well. – user3573403 Apr 11 '16 at 10:30

1 Answers1

12

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.

cassiomolin
  • 124,154
  • 35
  • 280
  • 359
  • This [question](http://stackoverflow.com/q/30258916/1426227) will give you some instructions on how to inject `ObjectMapper`. – cassiomolin Apr 11 '16 at 10:55
  • Hi, I think you have misunderstood my question. I want the extra field to be added in the request JSON message, before my web service is called. This is so that the web service will get the extra field. What you have proposed is adding the extra field in the response, which I already know how to do so. – user3573403 Apr 12 '16 at 01:33
  • You get an InputStream from the context. Then how am I supposed to get the JSON message and modify it? After that, you set the same InputStream to the context, which doesn't seem to make any sense to me. Could you show a more detailed example? – user3573403 Apr 12 '16 at 09:30
  • @user3573403 I've updated my answer with an example using Jackson. Let me know if it works for you. – cassiomolin Apr 12 '16 at 09:34
  • Thanks. Your latest solution works. Can this actually be done with a ContainerRequestFilter instead of ReaderInterceptor? – user3573403 Apr 13 '16 at 04:23
  • @user3573403 As stated in the [documentation](https://jersey.java.net/documentation/latest/filters-and-interceptors.html), *whereas __filters__ are primarily intended to manipulate request and response parameters like HTTP headers, URIs and/or HTTP methods, __interceptors__ are intended to manipulate entities, via manipulating entity input/output streams*. – cassiomolin Apr 13 '16 at 10:55