注释属性必须是类文本吗?为什么?常量也应该没问题

2022-09-04 21:43:17

有人可以解释为什么字符串和类注释参数的期望不同吗?为什么编译器需要类的文字,同时也接受字符串的常量?

Spring@RequestMapping的工作示例:

public class MyController {
    public static final String REQUEST_MAPPING = "/index.html";
    @RequestMapping(MyController.REQUEST_MAPPING) // ALL OK!
    ...
}

WTF示例与TestNG的@Test:

public class MyControllerTest {
    public static final Class TEST_EXCEPTION = RuntimeException.class;
    @Test(expectedExceptions = MyControllerTest.TEST_EXCEPTION) // compilation error, WTF:
    // The value for annotation attribute Test.expectedExceptions must be a class literal
    ...
}

当然,有效的是@Test(expectedExceptions = RuntimeException.class)。但是为什么?我看到的注释参数的唯一区别是它的类型:字符串与类。为什么Java编译器也接受String常量,但只接受类文本?


答案 1

Java 语言规范不允许您将编译时常量与 类型参数一起使用。只能使用类文本。Class

关于注释的合适参数值,JLS有以下说明:

当且仅当满足下列条件之一为真时,元素类型 T 与元素值 V 相称:

  • T 是数组类型 E[],并且:
    • VElementValueArrayInitializerV 中的每个 ElementValueInitializer(类似于数组初始值设定项中的变量初始值设定项)都与 E 相称。或
    • V 是与 T 相称的元素值
  • V 的类型与 T 的赋值兼容 (§5.2),此外:
    • 如果 T 是基元类型或字符串,则 V 是常量表达式 (§15.28)。
    • V 不为空。
    • 如果 T 是类,或者是类的调用,而 V 是类文字 (§15.8.2)。
    • 如果 T 是枚举类型,而 V 是枚举常量。

如果元素类型与 ElementValue 不相称,则为编译时错误。

但是,我不能说为什么JLS中有这种限制。


答案 2

我在以下内容上得到了“注释值必须是类文本”:

@ServerEndpoint(value="/story/notifications",
        encoders = (StickerEncoder.class),
        decoders = (StickerDecoder.class))

这是在遵循Oracles关于websockets的教程之一时发生的。事实证明,视频不是720p质量,模糊性隐藏了看起来像大括号的大括号。因此,在更改大括号的括号(括号)时,错误将消失。

@ServerEndpoint(value="/story/notifications",
        encoders = {StickerEncoder.class},
        decoders = {StickerDecoder.class})

任何将来可能会绊倒同样的人。


推荐