Search code examples
javadropwizardjava-11

Jersey Filters, Intercepter and MessageBodyReader using Dropwizard


I am exploring jersey filter in a dropwizard project. Trying to explore how incoming requests can be intercepted at a common place for every single endpoint to perform some basic checks on the request object (i.e. Path param, query param or request body) I am trying following interfaces

  • Filter
  • ContainerRequestFilter
  • ReaderInterceptor
  • MessageBodyReader

I am able to implement Filter and ContainerRequest Filter and see the code inside these implementation getting executed. However my ReaderInterceptor and MessageBodyReader is not getting executed.

Here is my code

PersonResource.java

@Path("person")
@Api("Person Resource")
@Log
@MyAnnotation
public class PersonResource {
  @GET
  @Path("{id}")
  @Produces(MediaType.APPLICATION_JSON)
  public Person getPerson(@PathParam("id") String id){
    log.info("Requesting Person information...");
    return new Person(id,"Person Name");
  }

}

Filter implementation

package com.practice.rigz.interceptor;


import lombok.extern.java.Log;

import javax.servlet.*;
import javax.ws.rs.ext.Provider;
import java.io.IOException;

@Provider
@Log
public class RequestFilter implements Filter {
  @Override
  public void init(FilterConfig filterConfig) throws ServletException {
  log.info("INIT...");
  }

  @Override
  public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    filterChain.doFilter(servletRequest,servletResponse);
    log.info("DO FILTER...");
  }

  @Override
  public void destroy() {
    log.info("DESTROY...");
  }

}

ContainerRequestFilter implementation

package com.practice.rigz.interceptor;

import com.practice.rigz.annotations.MyAnnotation;
import lombok.extern.java.Log;

import javax.ws.rs.container.*;
import javax.ws.rs.ext.Provider;
import java.io.IOException;
import java.util.List;

@Provider
@Log
@MyAnnotation
public class RequestContainerRequestFilter implements ContainerRequestFilter {
  @Override
  public void filter(ContainerRequestContext requestContext) throws IOException {
  log.info(String.join(","   ,requestContext.getPropertyNames()));
    List<String> partnerId = requestContext.getUriInfo().getPathParameters().get("id");
    if (partnerId.get(0).equals("1")){
      throw new IllegalAccessError();
    }
    log.info("CONTAINER REQUEST FILTER...");
  }

}

Reader Interceptor implementation

package com.practice.rigz.interceptor;

import com.practice.rigz.annotations.MyAnnotation;
import lombok.extern.java.Log;

import javax.ws.rs.WebApplicationException;
import javax.ws.rs.ext.Provider;
import javax.ws.rs.ext.ReaderInterceptor;
import javax.ws.rs.ext.ReaderInterceptorContext;
import java.io.IOException;

@Log
@MyAnnotation
@Provider
public class RequestReaderInterceptor implements ReaderInterceptor {
  @Override
  public Object aroundReadFrom(ReaderInterceptorContext readerInterceptorContext) throws IOException, WebApplicationException {
    log.info("INTERCEPTOR");
    return readerInterceptorContext.proceed();
  }
}

MessageBodyReader implementation

package com.practice.rigz.interceptor;

import com.practice.rigz.annotations.MyAnnotation;
import lombok.extern.java.Log;

import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.Provider;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;

@Provider
@Log
@MyAnnotation
public class RequestMessageBodyReader implements MessageBodyReader {
  @Override
  public boolean isReadable(Class aClass, Type type, Annotation[] annotations, MediaType mediaType) {
    log.info("IS READABLE...");
    return false;
  }

  @Override
  public Object readFrom(Class aClass, Type type, Annotation[] annotations, MediaType mediaType, MultivaluedMap multivaluedMap, InputStream inputStream) throws IOException, WebApplicationException {
    log.info("READ FROM ...");
    return null;
  }
}

and in my Dropwizard Application run method I am registering all the components as following

  private void registerFilters(Environment environment) {
     environment.servlets().addFilter("request-filter", RequestFilter.class)
       .addMappingForUrlPatterns(java.util.EnumSet.allOf(javax.servlet.DispatcherType.class), true, "/*");
     environment.jersey().register(RequestMessageBodyReader.class);
     environment.jersey().register(RequestReaderInterceptor.class);
     environment.jersey().register(RequestContainerRequestFilter.class);
  }

Any idea why my MessageBodyReader and ReaderInterceptor wont work? I am using OpenJDK11 and Dropwizard 1.3.16

Following is output of my program when try to hit the endpoint

INFO [2019-11-23 16:29:07,016] com.practice.rigz.interceptor.RequestContainerRequestFilter: org.glassfish.jersey.message.internal.TracingLogger INFO [2019-11-23 16:29:07,019] com.practice.rigz.interceptor.RequestContainerRequestFilter: CONTAINER REQUEST FILTER... INFO [2019-11-23 16:29:07,045] com.practice.rigz.resources.PersonResource: Requesting Person information... INFO [2019-11-23 16:29:07,119] com.practice.rigz.interceptor.RequestFilter: DO FILTER... 0:0:0:0:0:0:0:1 - - [23/Nov/2019:16:29:07 +0000] "GET /person/1111 HTTP/1.1" 200 34 "http://localhost:8080/swagger" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Safari/605.1.15" 242


Solution

  • I found cause of the issue. Few things i needed here

    1. Interceptor works for POST methods.
    2. MessageBodyReader also works for Post method since only POST can have body. I was always returning false from isReadableMethod. This method is supposed to return true if I want my implementation to handle a particular type of request. Changed the implementation to following
    package com.practice.rigz.interceptor;
    
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;
    import com.practice.rigz.annotations.MyAnnotation;
    import com.practice.rigz.model.Person;
    import lombok.extern.java.Log;
    import org.hibernate.validator.internal.util.privilegedactions.NewJaxbContext;
    
    import javax.ws.rs.WebApplicationException;
    import javax.ws.rs.core.Link;
    import javax.ws.rs.core.MediaType;
    import javax.ws.rs.core.MultivaluedMap;
    import javax.ws.rs.ext.MessageBodyReader;
    import javax.ws.rs.ext.Provider;
    import java.io.IOException;
    import java.io.InputStream;
    import java.lang.annotation.Annotation;
    import java.lang.reflect.Type;
    
    @Provider
    @Log
    @MyAnnotation
    public class RequestMessageBodyReader implements MessageBodyReader<Person> {
    
      @Override
      public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
        log.info("IS READABLE...");
        return type == Person.class;
      }
    
      @Override
      public Person readFrom(Class<Person> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream) throws IOException, WebApplicationException {
        ObjectMapper mapper = new ObjectMapper();
        Person person = mapper.readValue(entityStream, Person.class);
        log.info("READ FROM...");
        return person;
    
      }
    }