Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there an Interceptor in Jersey similar to that of Spring's HandlerInterceptor

I need an Interceptor in Jersey 2.x which gives references to request, response and the Method which matched the Path to a Web Service.

Something similar to HandlerInterceptor of Spring.

Requirements:

  1. Need Annotations used on Class - Perform the below checks, Only if the corresponding Method which needs to be invoked by jersey is NOT Annotated with a custom annotation.
  2. Request - To get/set attributes and get Session Object to validate user.
  3. Response - To re-direct the call in case any validation fails even before invoking the corresponding Methos.

Spring equivalent code:

public class WebServiceInterceptor implements HandlerInterceptor {
     @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        try {
            SkipWebServiceIntercept skipWebService = handler.getClass().getAnnotation(SkipWebServiceIntercept.class);

            if (skipWebService != null) {
                return Boolean.TRUE;
            }

            ...

            if(securityFails)
            {
                if ("XMLHttpRequest".equals(request.getHeader("X-Requested-With"))) {
                    response.setCharacterEncoding("utf-8");
                    response.setContentType("application/json");
                    PrintWriter out = response.getWriter();
                    String json;
                    ...
                    out.println(json);
                    return Boolean.FALSE;
                }
                else {
                    response.sendRedirect(redirectUrl);
                }
            }
            else
            {
                return Boolean.TRUE;
            }
        }catch (Exception e) {
            log.error("Exception in preHandle, redirecting to Login page", e);
            return LoginUtil.redirectToLogin(request, response);
        }
    }
}

I found references of

  1. ReaderInterceptor - This provides just Annotations of the Class. No access to request/response.
  2. ContainerRequestFilter - Provides Request Object but no Annotations/Response.
  3. ContainerResponseFilter - Gives Request & Response. But after the web-service/Method is invoked.

Is there anyother way this can be achieved without using Filters. because I need this processing to happen ONLY if the corresponding web-service is present. Filter's with /* on the other hand would always perform these validations even when the resource was not found.

Edit: Thanks to @peeskillet answer This is how I implemented it.

@Provider
public class ResourceInterceptor implements DynamicFeature {

    @Override
    public void configure(ResourceInfo resourceInfo, FeatureContext context) {

        System.out.println("Resource Interceptor called");

        if (resourceInfo.getResourceClass() != null
                && resourceInfo.getResourceClass().getAnnotation(SkipWebServiceIntercept.class) != null)
            return;

        context.register(LoginFilter.class);
    }

}


@Slf4j
public class LoginFilter implements ContainerRequestFilter {

    @Context
    private HttpServletRequest      request;

    @Context
    private ServletContext          servletContext;

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        try {


WebApplicationContext springContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);

CookieAuthenticator cookieAuthenticator = springContext.getBean(CookieAuthenticator.class);

HttpSession session = request.getSession(true);

...

// Sending JSON/Object back as response

...
String json = gson.toJson(resposeJson);

Response response = new ResponseBuilderImpl().encoding(StandardCharsets.UTF_8.name())
                        .type(MediaType.APPLICATION_JSON).entity(json).build();
requestContext.abortWith(response);
...

// or Sending URL back

...
URI uri = new URI(baseUrl + redirectUrl + "?refback=" + url);
requestContext.abortWith(Response.temporaryRedirect(uri).build());
...

Both the approaches worked perfectly, similar to HandlerInterceptor of Spring.

like image 457
Kishore Bandi Avatar asked Oct 19 '22 14:10

Kishore Bandi


1 Answers

Is there anyother way this can be achieved without using Filters. because I need this processing to happen ONLY if the corresponding web-service is present. Filter's with /* on the other hand would always perform these validations even when the resource was not found.

There are different ways to register a filter.

  1. Just register it normally, where the result is the filter always getting called. (what you don't want).

  2. Registered with an annotation, though name binding. This way, only resource annotated will go through the filter. (this is kind of what you want, only problem is you would need to annotate every class)

    @Target({TYPE, METHOD})
    @Retention(RetentionPolicy.RUNTIME);
    class @interface Filtered {}
    
    @Path("..")
    @Filtered
    public class YourResource {}
    
    @Filtered
    @Provider
    public class YourFilter implements ContainerRequestFilter {}
    
  3. Use a DynamicFeature to bind resource programmatically, rather than declaratively. The DynamicFeture will get called for each of your resource methods, so you can just register the filter for every call. This has the same affect as annotating every resource class (as mentioned above) with name binding (this is probably what you want).

    @Provider
    public class MyFeature implements DynamicFeature {
        @Override
        public void configure(ResourceInfo ri, FeatureContext ctx) {
            ctx.register(YourFilter.class);
        }
    }
    

See Also:

  • Chapter 10. Filters and Interceptors
like image 95
Paul Samsotha Avatar answered Oct 27 '22 10:10

Paul Samsotha