Java - 自定义注释不会被考虑

时间:2017-08-18 16:41:09

标签: java interface annotations jax-rs

我构建了一个EmployeeEndpoint,它包含不同的方法,如create,update,remove等等。为了简化这个问题,我只使用了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中捕获权限注释时#39; ContainerRequestFilter接口方法调用filter我得到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帖子。

AuthorizationFilter

@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");
        }
    }
}

1 个答案:

答案 0 :(得分:0)

您的代码看起来不错。

我已经运行了一些测试,我能想到的唯一原因是您在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;
}