使用 Enum 类型作为 @RolesAllowed-Annotation 的值参数

2022-01-13 00:00:00 annotations enums jakarta-ee java java-ee-6

我正在开发一个 Java 企业应用程序,目前正在做 Java EE 安全工作,以限制特定用户对特定功能的访问.我配置了应用程序服务器和所有内容,现在我使用 RolesAllowed-annotation 来保护方法:

I'm developing a Java enterprise application, currently doing Java EE security stuff to restrict access for particular functions to specific users. I configured the application server and everything, and now I'm using the RolesAllowed-annotation to secure the methods:

@Documented
@Retention (RUNTIME)
@Target({TYPE, METHOD})
public @interface RolesAllowed {
    String[] value();
}

当我像这样使用注释时,它工作正常:

When I use the annotation like this, it works fine:

@RolesAllowed("STUDENT")
public void update(User p) { ... }

但这不是我想要的,因为我必须在这里使用字符串,重构变得困难,并且可能会发生拼写错误.因此,我不想使用字符串,而是使用枚举值作为此注释的参数.枚举看起来像这样:

But this is not what I want, as I have to use a String here, refactoring becomes hard, and typos can happen. So instead of using a String, I would like to use an Enum value as a parameter for this annotation. The Enum looks like this:

public enum RoleType {
    STUDENT("STUDENT"),
    TEACHER("TEACHER"),
    DEANERY("DEANERY");

    private final String label;

    private RoleType(String label) {
        this.label = label;
    }

    public String toString() {
        return this.label;
    }
}

所以我尝试使用 Enum 作为这样的参数:

So I tried to use the Enum as a parameter like this:

@RolesAllowed(RoleType.DEANERY.name())
public void update(User p) { ... }

然后我得到以下编译器错误,尽管 Enum.name 只返回一个字符串(它始终是常量,不是吗?).

But then I get the following compiler error, although Enum.name just returns a String (which is always constant, isn't it?).

注解属性RolesAllowed.value的值必须是常量表达式`

The value for annotation attribute RolesAllowed.value must be a constant expression`

接下来我尝试在我的枚举中添加一个额外的最终字符串:

The next thing I tried was to add an additional final String to my Enum:

public enum RoleType {
    ...
    public static final String STUDENT_ROLE = STUDENT.toString();
    ...
}

但这也不能作为参数起作用,导致同样的编译器错误:

But this also doesn't work as a parameter, resulting in the same compiler error:

// The value for annotation attribute RolesAllowed.value must be a constant expression
@RolesAllowed(RoleType.STUDENT_ROLE)

如何实现我想要的行为?我什至实现了自己的拦截器来使用自己的注释,这很漂亮,但是对于这样的小问题,代码行数太多了.

How can I achieve the behavior I want? I even implemented my own interceptor to use my own annotations, which is beautiful, but far too much lines of codes for a little problem like this.

免责声明

这个问题最初是一个 Scala 问题.我发现 Scala 不是问题的根源,所以我首先尝试在 Java 中执行此操作.

This question was originally a Scala question. I found out that Scala is not the source of the problem, so I first try to do this in Java.

推荐答案

我认为您使用枚举的方法行不通.我发现如果我将最后一个示例中的 STUDENT_ROLE 字段更改为常量字符串,而不是表达式,编译器错误就会消失:

I don't think your approach of using enums is going to work. I found that the compiler error went away if I changed the STUDENT_ROLE field in your final example to a constant string, as opposed to an expression:

public enum RoleType { 
  ...
  public static final String STUDENT_ROLE = "STUDENT";
  ...
}

但是,这意味着枚举值不会在任何地方使用,因为您将在注释中使用字符串常量.

However, this then means that the enum values wouldn't be used anywhere, because you'd be using the string constants in annotations instead.

在我看来,如果你的 RoleType 类只包含一堆静态的 final String 常量,你会做得更好.

It seems to me that you'd be better off if your RoleType class contained nothing more than a bunch of static final String constants.

要了解您的代码未编译的原因,我查看了 Java 语言规范 (JLS).annotations 的 JLS 声明对于注释带有 T 类型的参数和值 V,

To see why your code wasn't compiling, I had a look into the Java Language Specification (JLS). The JLS for annotations states that for an annotation with a parameter of type T and value V,

如果T 是原始类型或String,则V 是常量表达式.

if T is a primitive type or String, V is a constant expression.

常量表达式包括,其中其他的,

TypeName 形式的限定名称.标识符表示常量变量

Qualified names of the form TypeName . Identifier that refer to constant variables

并且定义了一个常量变量作为

原始类型或 String 类型的变量,它是最终的并使用编译时常量表达式进行初始化

a variable, of primitive type or type String, that is final and initialized with a compile-time constant expression

相关文章