我正在开发一个Java企业应用程序,目前正在执行Java EE安全性工作,以限制特定用户对特定功能的访问。我配置了应用服务器和所有内容,现在我使用RolesAllowed-annotation来保护方法:
@Documented
@Retention (RUNTIME)
@Target({TYPE, METHOD})
public @interface RolesAllowed {
String[] value();
}
当我像这样使用注解时,它工作得很好:
@RolesAllowed("STUDENT")
public void update(User p) { ... }
但这不是我想要的,因为我必须在这里使用String,重构变得很困难,而且可能会出现拼写错误。因此,我不使用String,而是使用Enum值作为此注解的参数。Enum如下所示:
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作为一个参数,如下所示:
@RolesAllowed(RoleType.DEANERY.name())
public void update(User p) { ... }
但是我得到了下面的编译器错误,尽管Enum.name只返回了一个String(它总是常量,不是吗?)
注解属性RolesAllowed的值。值必须是常量表达式'
接下来,我尝试向Enum添加一个额外的final String:
public enum RoleType {
...
public static final String STUDENT_ROLE = STUDENT.toString();
...
}
但这也不能作为参数使用,导致同样的编译器错误:
// The value for annotation attribute RolesAllowed.value must be a constant expression
@RolesAllowed(RoleType.STUDENT_ROLE)
我怎样才能实现我想要的行为呢?我甚至实现了我自己的拦截器来使用我自己的注解,这很漂亮,但是对于像这样的小问题来说,代码行太多了。
免责声明
这个问题本来是一个Scala问题,我发现Scala不是问题的根源,所以我首先尝试用Java来做这个。
5条答案
按热度按时间hm2xizp91#
这个怎么样?
在注解中,您可以像这样使用它
有一点需要注意的是,对于任何修改,我们都需要在两个地方进行更改。但是由于它们位于同一个文件中,因此不太可能会错过。作为回报,我们得到了不使用原始字符串和避免复杂机制的好处。
或者这听起来完全愚蠢?:)
kzipqqlq2#
我不认为你使用枚举的方法会起作用,我发现如果我把最后一个例子中的
STUDENT_ROLE
字段改为常量字符串,而不是表达式,编译器错误就会消失:然而,这意味着枚举值不会在任何地方使用,因为您将在注解中使用字符串常量。
在我看来,如果您的
RoleType
类只包含一堆静态的final String常量,您会过得更好。为了了解代码为什么不能编译,我查看了Java Language Specification(JLS)。注解的JLS声明,对于参数类型为 T、值为 V 的注解,
如果 T 是基元类型或
String
,则 V 是常量表达式。常量表达式包括,除其他外,
引用常量变量的 TypeName . Identifier 格式的限定名称
常量变量定义为
一个基元类型或
String
类型的变量,它是final变量,并使用编译时常量表达式初始化nszi6y053#
下面是一个使用附加接口和元注解的解决方案,我包含了一个实用程序类来帮助执行反射,以便从一组注解中获取角色类型,并对它进行了一些测试:
ds97pgxw4#
我使用Lombok注解
FieldNameConstants
解决了这个问题:接下来,您可以按如下方式使用它:
smtd7mpg5#
我通过添加注解
@RoleTypesAllowed
和添加元数据源解决了这个问题。如果只有一个枚举类型需要支持,这会非常有效。对于多个枚举类型,请参阅anomolos的帖子。下面的
RoleType
是我的角色枚举。然后我向Spring添加了以下元数据源...