Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Annotation attribute must be a class literal? Why? Constants should be fine too

Tags:

java

jls

testng

Can someone explain why String and Class annotation parameters are expected differently? Why does the compiler require literals for Classes, wherby accepting constants for Strings as well?

Working example with Spring's @RequestMapping:

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

WTF example with TestNG's @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
    ...
}

What does work of course is @Test(expectedExceptions = RuntimeException.class). But why? The only difference in the annotation parameter I see is its type: String vs Class. Why on earth would the Java compiler accept String constant as well but accept only class literals?

like image 673
sibidiba Avatar asked Dec 22 '11 13:12

sibidiba


2 Answers

The Java Language Specification doesn't permit you to use compile-time constants with parameters of type Class. You can only use class literals.

The JLS has the following to say about suitable parameter values for annotations:

An element type T is commensurate with an element value V if and only if one of the following conditions is true:

  • T is an array type E[] and either:
    • V is an ElementValueArrayInitializer and each ElementValueInitializer (analogous to a variable initializer in an array initializer) in V is commensurate with E. Or
    • V is an ElementValue that is commensurate with T.
  • The type of V is assignment compatible (§5.2) with T and, furthermore:
    • If T is a primitive type or String, V is a constant expression (§15.28).
    • V is not null.
    • if T is Class, or an invocation of Class, and V is a class literal (§15.8.2).
    • If T is an enum type, and V is an enum constant.

It is a compile-time error if the element type is not commensurate with the ElementValue.

I can't say why this restriction is in the JLS, however.

like image 191
Luke Woodward Avatar answered Sep 27 '22 17:09

Luke Woodward


I got the "annotation value must be a class literal" on the following:

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

This happening whilst following one of Oracles tutorials on websockets. Turns out the video is not the 720p quality and the fuzziness hides the braces which look like curly brackets. So the error disappears upon changing brackets (parentheses) for braces.

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

hth anyone who may trip over the same in the future.

like image 26
buzzzz717 Avatar answered Sep 27 '22 17:09

buzzzz717