Як надати значення анотації з постійної 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
  • [...] оператори [...]
  • Парентезовані вирази, чий міститься вираз є постійним виразом.
  • Прості імена, що посилаються на постійні змінні.
  • Кваліфіковані назви форми TypeName . Ідентифікатор, що відноситься до постійних змінних.

Насправді в Java не існує способу захисту елементів у масиві. Під час виконання хтось завжди може це зробити FieldValues.FIELD1[0]="value3", тому масив не може бути дійсно постійним, якщо ми дивимося глибше.


14
Енуми теж! :) :)
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константу можна передати прямо в примітку.

Навiть, я не пригадую, щоб коли-небудь пробував це з масивом, тому, можливо, ви стикаєтесь з деякими проблемами з невеликими відмінностями в тому, як масиви представлені як параметри анотації порівняно зі змінними Java? Але що стосується іншої частини вашого питання, ви, безумовно, можете безперервно використовувати постійний рядок.

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


1
Жорстока удача для мене! О так, я зміг пропустити рядки / номери, але не масиви. Я витрачу на це трохи більше часу, і якщо нічого не вийде, я прийму відповідь :)
Каннан Еканат

Так, я можу припустити, що тут змінюється зміна масиву FIELD1. Ви можете оголосити масив ініціалізатором масиву, тому що більше нічого не може мати доступ до цього масиву, тому він не може бути змінений пізніше.
ColinD

Це вирішує мою проблему. Просто потрібно поділити константу String між примітками та кодом. Дякую!
симон

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 [], щоб надати значення для анотації?

На жаль, ви не можете зробити це з масивами. Для змінних без масиву значення повинно бути кінцевим статичним.


5

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

Завдяки Seam 2 http://seamframework.org/ ви змогли вирішити параметри анотації під час виконання, з мовою виразу всередині подвійних лапок.

У Seam 3 http://seamframework.org/Seam3/Solder цією функцією є модуль Seam Solder


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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.