How to supply value to an annotation from a Constant java
Asked Answered
O

6

192

I am thinking this may not be possible in Java because annotation and its parameters are resolved at compile time. I have an interface as follows,

public interface FieldValues {
   String[] FIELD1 = new String[]{"value1", "value2"};
}

and another class as,

@SomeAnnotation(locations = {"value1", "value2"})
public class MyClass {
   ....
}

I mark many classes with the annotation and I would like to know if I can avoid specifying the strings in every annotation I would instead prefer to use

@SomeAnnotation(locations = FieldValues.FIELD1)
public class MyClass {
   ....
}

However this gives compilation errors like annotation value should be an array initializer etc. Does someone know how I can use a String constant or String[] constant to supply value to an annotation?

Ovate answered 14/1, 2010 at 17:2 Comment(0)
S
158

Compile constants can only be primitives and Strings:

15.28. Constant Expressions

A compile-time constant expression is an expression denoting a value of primitive type or a String that does not complete abruptly and is composed using only the following:

  • Literals of primitive type and literals of type String
  • Casts to primitive types and casts to type String
  • [...] operators [...]
  • Parenthesized expressions whose contained expression is a constant expression.
  • Simple names that refer to constant variables.
  • Qualified names of the form TypeName . Identifier that refer to constant variables.

Actually in java there is no way to protect items in an array. At runtime someone can always do FieldValues.FIELD1[0]="value3", therefore the array cannot be really constant if we look deeper.

Stooge answered 14/1, 2010 at 21:57 Comment(6)
@TacB0sS, enums are not constant expressions.Counterpart
Well... perhaps you should give it a go and let me know... I use them all the time :)Marcellmarcella
A more relevant spec is under Annotations. In addition to a constant expression, an annotation value can be an array initializer, class literal, or enum constant.Counterpart
Aha! I was using a Long, not a long..... Solved my issue!!! Thanks!!!!!!!!!!!!!!!Yoghurt
@Marcellmarcella you can use enum in annotatios, but they are not compile-time constant. The difference becomes apparent when you write static final EnumType VARIABLE = EnumType.ENUM_CONSTANT; and try to use VARIABLE in an annotation; it won’t work. You can only use EnumType.ENUM_CONSTANT which is not a constant expression, but specifically allowed in annotations (and switch statements).Weidar
Wow! Totally blown away with this revelation after years of doing Java. Was using Integer and pulling my hair.Yseulta
W
51

You can use a constant (i.e. a static, final variable) as the parameter for an annotation. As a quick example, I use something like this fairly often:

import org.junit.Test;
import static org.junit.Assert.*;

public class MyTestClass
{
    private static final int TEST_TIMEOUT = 60000; // one minute per test

    @Test(timeout=TEST_TIMEOUT)
    public void testJDK()
    {
        assertTrue("Something is very wrong", Boolean.TRUE);
    }
}

Note that it's possible to pass the TEST_TIMEOUT constant straight into the annotation.

Offhand, I don't recall ever having tried this with an array, so you may be running into some issues with slight differences in how arrays are represented as annotation parameters compared to Java variables? But as for the other part of your question, you could definitely use a constant String without any problems.

EDIT: I've just tried this with a String array, and didn't run into the problem you mentioned - however the compiler did tell me that the "attribute value must be constant" despite the array being defined as public static final String[]. Perhaps it doesn't like the fact that arrays are mutable? Hmm...

Webworm answered 14/1, 2010 at 17:12 Comment(5)
Tough Luck for me ! Oh yah I was able to pass Strings/Numbers but not arrays. I will spend a bit more time on this and if nothing works out will accept the answer :)Ovate
Yeah, my guess would be that the mutability of the FIELD1 array is the issue here. You're allowed to declare the array with an array initializer because nothing else can have access to that array and so it cannot be changed later.Gobi
This solves my problem. Just needed to share a String constant between annotations and code. Thanks!Stlouis
static final variable is not the only prerequisite. If you try to dynamically calc the variable you'll get the same error message.Radiograph
static final does not mean "constant". The sample works because int is constant.Mares
P
14

Does someone know how I can use a String constant or String[] constant to supply value to an annotation?

Unfortunately, you can't do this with arrays. With non-array variables, the value must be final static.

Pothole answered 14/1, 2010 at 17:7 Comment(1)
It must be final but does not have to be static.Trichocyst
S
12

You're not supplying it with an array in your example. The following compiles fine:

public @interface SampleAnnotation {
    String[] sampleValues();
}

public class Values {
    public static final String val0 = "A";
    public static final String val1 = "B";

    @SampleAnnotation(sampleValues={ val0, val1 })
    public void foo() {
    }
}
Spindlelegs answered 14/1, 2010 at 17:19 Comment(1)
It is being supplied with an array in the example, just not one that is created directly in the annotation declaration.Gobi
M
5

I am thinking this may not be possible in Java because annotation and its parameters are resolved at compile time.

With Seam 2 http://seamframework.org/ you were able to resolve annotation parameters at runtime, with expression language inside double quotes.

In Seam 3 http://seamframework.org/Seam3/Solder, this feature is the module Seam Solder

Monotony answered 9/11, 2011 at 23:28 Comment(1)
No, you didn't resolve the parameters at runtime. The parameter were resolved at compile-time. That they were then used to do something at runtime has literally nothing to do with when their values were set.Raila
A
-3

You can use enum and refer that enum in annotation field

Arrangement answered 6/4, 2020 at 14:19 Comment(1)
You should add an example.Joselow

© 2022 - 2024 — McMap. All rights reserved.