Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
157 views
in Technique[技术] by (71.8m points)

java - 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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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
    }
  }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...