【问题标题】:Java – custom annotation won't be consideredJava – 不考虑自定义注解
【发布时间】:2017-08-18 16:41:08
【问题描述】:

我已经构建了一个 EmployeeEndpoint,它包含不同的方法,例如创建、更新、删除等等。为了简化这个问题,我只使用了 create 方法。

因为我想要一个可扩展的应用程序,所以我构建了一个包含基本方法的接口。在界面中,我现在可以使用 JAX-RS-Annotations 对方法进行注释。因为它们将被继承,所以我只需要覆盖 EmployeeEndpoint 中的接口方法。

界面

public interface RESTCollection<T> {
    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public T create(T entity) throws Exception;
}

端点

@Stateless
@Path(“employee“)
public class EmployeeEndpoint implements RESTCollection<Employee> {
    @Override
    public Employee create(Employee employee) throws Exception {
        return this.createEmployee(employee);
    }
}

上面的例子运行良好。如果我想添加自定义注释,我可以这样做:

解决方案 1

public interface RESTCollection<T> {
    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    @Permissions(Role.Admin)
    public T create(T entity) throws Exception;
}

解决方案 2

@Stateless
@Path(“employee“)
public class EmployeeEndpoint implements RESTCollection<Employee> {
    @Override
    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    @Permissions(Role.Admin)
    public Employee create(Employee employee) throws Exception {
        return this.createEmployee(employee);
    }
}

但解决方案 1 不是一个好主意,因为并非每个实体都只能由管理员创建。使用解决方案 2 我失去了可扩展性和注释代码更少的优势。所以最好的方法是:

解决方案 3

@Stateless
@Path(“employee“)
public class EmployeeEndpoint implements RESTCollection<Employee> {
    @Override
    @Permissions(Role.Admin)
    public Employee create(Employee employee) throws Exception {
        return this.createEmployee(employee);
    }
}

但是现在,当我在 JAX-RS 的 ContainerRequestFilter 接口方法(称为 filter)中捕获 Permissions-Annotation 时,我得到了 null 的值,我不明白。

@Context
private ResourceInfo resourceInfo;

resourceInfo.getResourceMethod().getAnnotation(Permissions.class) // is null

注释

@NameBinding
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface Permissions {
    Role[] value() default {};
}

枚举

public enum Role {
    Admin,
    User
}

是否有可能采用解决方案 3 或我具有相同优势的不同方法?

更新

因为原因似乎不是我发布的代码,所以我将向您展示我的 AuthorizationFilter。因此我使用了this 发帖。

授权过滤器

@Provider
@Priority(Priorities.AUTHORIZATION)
public class AuthorizationFilter implements ContainerRequestFilter {

    @Inject
    @AuthenticatedUser
    private User authenticatedUser;

    @Context
    private ResourceInfo resourceInfo;

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

        Class<?> resourceClass = resourceInfo.getResourceClass();
        List<Role> classRoles = extractRoles(resourceClass);

        Method resourceMethod = resourceInfo.getResourceMethod();
        List<Role> methodRoles = extractRoles(resourceMethod);

        try {

            if (methodRoles.isEmpty()) checkPermissions(classRoles, requestContext.getHeaderString(HttpHeaders.AUTHORIZATION));
            else checkPermissions(methodRoles, requestContext.getHeaderString(HttpHeaders.AUTHORIZATION));

        } catch (NotAuthorizedException e) {
            requestContext.abortWith(
                    Response.status(Response.Status.UNAUTHORIZED).build());
        } catch (Exception e) {
            requestContext.abortWith(
                    Response.status(Response.Status.FORBIDDEN).build());
        }
    }

    private List<Role> extractRoles(AnnotatedElement annotatedElement) {
        if (annotatedElement == null) return new ArrayList<Role>();
        else {
            Permissions perms = annotatedElement.getAnnotation(Permissions.class);
            if (perms == null) return new ArrayList<Role>();
            else {
                Role[] allowedRoles = perms.value();
                return Arrays.asList(allowedRoles);
            }
        }
    }

    private void checkPermissions(List<Role> allowedRoles, String authorizationHeader) throws NotAuthorizedException, Exception {
        if (!allowedRoles.isEmpty()) {
            if (authorizationHeader == null || !authorizationHeader.startsWith("Bearer "))
                throw new NotAuthorizedException("Authorization header must be provided");
            else if (!allowedRoles.contains(this.authenticatedUser.getRole()))
                throw new Exception("User has no permissions");
        }
    }
}

【问题讨论】:

  • “根本不考虑权限”是什么意思?
  • 当我在名为 filter 的 JAX-RS 的 ContainerRequestFilter 接口方法中捕获 Permissions-Annotation 时,我得到了 null 的值。
  • 刚刚测试过,它工作正常。您收到 NullPointerException 还是调用结果为 null?
  • 调用结果为null。

标签: java interface annotations jax-rs


【解决方案1】:

您的代码看起来不错。

我已经进行了一些测试,我能想到的唯一原因是您在 Employee 资源上使用了 2 种不同的 Permission 类型,而不是在过滤器上使用的类型。 (检查你的进口)

不确定您的 Filter 代码,但这是我的工作(请参阅导入):

package com.app.filters; // TODO change this with yours

import java.io.IOException;
import java.util.Arrays;

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ResourceInfo;
import javax.ws.rs.core.Context;

import com.app.services.Permissions; // TODO change this with yours

public class AuthorizationFilter implements ContainerRequestFilter {

    @Context
    ResourceInfo resourceInfo;

    @Override
    public void filter (ContainerRequestContext requestContext) throws IOException {
        Permissions perms   = resourceInfo.getResourceMethod ().getAnnotation (Permissions.class);

        System.out.println (getClass ().getSimpleName () + " --> Permissions: " + Arrays.toString (perms.value ())); // prints [Admin]
    }

}

奖励,如果您想测试 Employee 资源上注释的实际值:

....
import com.app.services.Permissions; // TODO change this with yours (the one on the filter being the same as this one)
....

@Permissions (Role.Admin)
@Override
public Employee create (Employee employee) throws Exception {
    Class<?> [] cArg    = new Class [1];
    cArg [0]            = Employee.class;

    Method method       = getClass ().getMethod ("create", cArg);
    Permissions perms   = method.getAnnotation (Permissions.class);

    System.out.println (EmployeeService.class.getSimpleName () + " --> Permissions: " + Arrays.toString (perms.value ()));

    return null;
}

【讨论】:

  • 我也有同样的想法,但这并不能解释为什么解决方案 1 和 2 有效。这是假设 OP 实际测试了 1 和 2。
  • 感谢您的回答!这不是导入问题,我的 AuthorizationFilter 与您的非常相似。但我更新了我的问题并发布了 AuthorizationFilter,以防万一。
猜你喜欢
  • 2014-03-09
  • 2014-01-13
  • 1970-01-01
  • 1970-01-01
  • 2014-05-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-06
相关资源
最近更新 更多