Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get resource class annotation values inside ContainerRequestFilter

I'm struggling a bit with understanding how rest interceptor annotations can add different values that are later visible in the filter. Given the code below I would expect that once in the filter the permissions values would have foo and bar in them, however they are empty. Any help would be greatly appreciated.

Annotation

package edu.psu.swe.fortress.poc.interceptor;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.enterprise.util.Nonbinding;
import javax.ws.rs.NameBinding;

@NameBinding
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(value=RetentionPolicy.RUNTIME)
public @interface FortressProtected
{
  @Nonbinding String[] permissions() default {};
}

Filter

package edu.psu.swe.fortress.poc.interceptor;

import java.io.IOException;
import java.lang.annotation.Annotation;

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.ext.Provider;

@Provider
@FortressProtected
public class FortressAuthorizer implements ContainerRequestFilter
{

  @Override
  public void filter(ContainerRequestContext requestContext) throws     IOException
  {
    System.out.println("In the interceptor");
    Class<?> clazz = this.getClass();
    FortressProtected annotation = clazz.getAnnotation(edu.psu.swe.fortress.poc.interceptor.FortressProtected.class);

    System.out.println("Annotation? " + clazz.isAnnotation());

    for (Annotation a : clazz.getAnnotations())
    {
      System.out.println(a);
    }

    for (String s : annotation.permissions())
    {
      System.out.println(s);
    }
  }
}

App config

package edu.psu.swe.fortress.poc.rest;

import java.util.HashSet;
import java.util.Set;

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

import edu.psu.swe.fortress.poc.interceptor.FortressAuthorizer;
import edu.psu.swe.fortress.poc.interceptor.FortressProtected;

@ApplicationPath("")
public class FortressTestApp extends Application
{
  private Set<Class<?>> clazzez_ = new HashSet<>();
  {
    clazzez_.add(ResourceImpl.class);
    clazzez_.add(FortressProtected.class);
    clazzez_.add(FortressAuthorizer.class);
  }
  public Set<Class<?>> getClasses()
  {
    return clazzez_;
  }
}

Resource class

package edu.psu.swe.fortress.poc.rest;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

import edu.psu.swe.fortress.poc.interceptor.FortressProtected;

@FortressProtected(permissions={"foo", "bar"})
@Path("tests")
public class ResourceImpl
{
  @GET
  @Produces("application/text")
  public String getHello()
  {
    FortressProtected annotation = this.getClass().getAnnotation(edu.psu.swe.fortress.poc.interceptor.FortressProtected.class);

    System.out.println(annotation.toString());

    return "hello";
  }
}

Log output looks like:

15:59:55,223 INFO [stdout] (default task-9) @edu.psu.swe.fortress.poc.interceptor.FortressProtected(permissions=[]) 15:59:55,229 INFO [stdout] (default task-9) @edu.psu.swe.fortress.poc.interceptor.FortressProtected(permissions=[foo, bar])

Thanks in advance.

like image 967
Shawn Eion Smith Avatar asked Mar 22 '15 19:03

Shawn Eion Smith


1 Answers

Look at this in your filter

Class<?> clazz = this.getClass();
FortressProtected annotation = clazz.getAnnotation(FortressProtected.class);

this.getClass() corresponds to the filter class (whose annotation has no values). You instead need to get the annotation on the ResourceImpl

A couple options. You could explicitly use ResourceImpl.class.getAnnotation(...). But the problem with this is that once you bind more than one class, how do you match which class corresponds to which request. For that reason, the next option is more viable.

What you do is inject ResourceInfo. With this, you can call it's getResourceMethod or getResourceClass methods. These methods return the matched method and class, respectively. You could then check for the annotation at the class level as well as the method level (as we are also allowed to bind at the method level). So you might have something more like:

@Provider
@FortressProtected
public class FortressAuthorizer implements ContainerRequestFilter {

  @Context
  ResourceInfo resourceInfo;

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

    Class<?> resourceClass = resourceInfo.getResourceClass();
    FortressProtected classAnnot = resourceClass.getAnnotation(FortressProtected.class);
    if (classAnnot != null) {
      // do something with annotation
    }

    Method resourceMethod = resourceInfo.getResourceMethod();
    FortressProtected methodAnnot = resourceMethod.getAnnotation(FortressProtected.class);
    if (methodAnnot != null) {
      // do something with annotation
    }
  }
}
like image 166
Paul Samsotha Avatar answered Oct 06 '22 10:10

Paul Samsotha