Как придать значение аннотации из константы Java

146

Я думаю, что это может быть невозможно в Java, потому что аннотация и ее параметры разрешаются во время компиляции. У меня есть интерфейс следующим образом,

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

и другой класс как,

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

Я отмечаю многие классы аннотацией, и я хотел бы знать, могу ли я избежать указания строк в каждой аннотации, которую я вместо этого предпочел бы использовать

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

Однако это приводит к ошибкам компиляции, таким как значение аннотации должно быть инициализатором массива и т. Д. Кто-нибудь знает, как я могу использовать константу String или константу String [] для предоставления значения аннотации?

Каннан Эканат
источник

Ответы:

127

Константы компиляции могут быть только примитивами и строками :

15,28. Постоянные выражения

Выражение константы во время компиляции - это выражение, обозначающее значение типа примитива или String, которое не завершается внезапно и составляется с использованием только следующего:

  • Литералы примитивного типа и литералы типа String
  • Приведения к примитивным типам и приведение к типу String
  • [...] операторы [...]
  • Выражения в скобках, содержащиеся выражения которых являются константными.
  • Простые имена, которые ссылаются на постоянные переменные.
  • Квалифицированные имена в форме TypeName . Идентификатор, который ссылается на постоянные переменные.

На самом деле в Java нет способа защитить элементы в массиве. Во время выполнения кто-то всегда может это сделать FieldValues.FIELD1[0]="value3", поэтому массив не может быть действительно постоянным, если мы посмотрим глубже.

irreputable
источник
14
Enums тоже! :) :)
TacB0sS
1
@ TacB0sS, перечисления не являются константными выражениями.
jaco0646
Ну ... возможно, тебе стоит попробовать и дать мне знать ... Я использую их все время :)
TacB0sS
4
Более актуальная спецификация находится под аннотациями . В дополнение к константному выражению значением аннотации может быть инициализатор массива , литерал класса или константа перечисления .
jaco0646
3
@ TacB0sS вы можете использовать enumв аннотациях, но они не являются константами времени компиляции. Разница становится очевидной, когда вы пишете static final EnumType VARIABLE = EnumType.ENUM_CONSTANT;и пытаетесь использовать VARIABLEв аннотации; это не сработает. Вы можете использовать только то, EnumType.ENUM_CONSTANTкоторое не является константным выражением, но специально разрешено в аннотациях (и switchутверждениях).
Хольгер
37

Вы можете использовать константу (то есть статическую, конечную переменную) в качестве параметра для аннотации. В качестве быстрого примера я использую что-то вроде этого довольно часто:

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);
    }
}

Обратите внимание, что TEST_TIMEOUTконстанту можно передать прямо в аннотацию.

Случайно, я не помню, чтобы когда-либо пробовал это с массивом, поэтому вы можете столкнуться с некоторыми проблемами с небольшими различиями в том, как массивы представляются как параметры аннотации по сравнению с переменными Java? Но что касается другой части вашего вопроса, вы можете без проблем использовать постоянную строку.

EDIT: Я просто попытался это с массивом Струнный и не столкнуться с проблемой , вы упомянули - однако компилятор ничего сказать мне , что «значение атрибута должно быть постоянной» , несмотря на массив определяется как public static final String[]. Возможно, ему не нравится тот факт, что массивы изменчивы? Хм ...

Анджей Дойл
источник
1
Удачи мне! О, да, я смог передать строки / числа, но не массивы. Я потрачу немного больше времени на это, и если ничего не получится, приму ответ :)
Kannan Ekanath
Да, я думаю, что проблема заключается в изменчивости массива FIELD1. Вы можете объявить массив с инициализатором массива, потому что ничто другое не может иметь доступ к этому массиву, и поэтому его нельзя изменить позже.
ColinD
Это решает мою проблему. Просто нужно было разделить строковую константу между аннотациями и кодом. Спасибо!
Симон
1
Статическая конечная переменная - не единственное условие. Если вы попытаетесь динамически вычислить переменную, вы получите то же сообщение об ошибке.
Вольфганг Фал
11

Вы не предоставляете ему массив в вашем примере. Следующее компилируется нормально:

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() {
    }
}
Стив Б.
источник
4
В примере он поставляется с массивом, но не с тем, который создается непосредственно в объявлении аннотации.
ColinD
7

Кто-нибудь знает, как я могу использовать константу String или константу String [] для предоставления значения аннотации?

К сожалению, вы не можете сделать это с массивами. С переменными, не являющимися массивами, значение должно быть окончательным статическим.

Kevin
источник
5

Я думаю, что это может быть невозможно в Java, потому что аннотация и ее параметры разрешаются во время компиляции.

С помощью Seam 2 http://seamframework.org/ вы смогли разрешить параметры аннотаций во время выполнения с помощью языка выражений в двойных кавычках.

В Seam 3 http://seamframework.org/Seam3/Solder эта функция представляет собой модуль Seam Solder

jorgwel
источник
3
Нет, вы не разрешили параметры во время выполнения. Параметр был разрешен во время компиляции. То, что они затем использовались для выполнения чего-либо во время выполнения, буквально не имеет ничего общего с тем, когда их значения были установлены.
Фонд Моники иск
1

Вы можете использовать enum и ссылаться на enum в поле аннотации.

Kaustubh Thawari
источник
1
Вы должны добавить пример.
m02ph3u5