Jak dodać wartość do adnotacji z Constant java

146

Myślę, że może to nie być możliwe w Javie, ponieważ adnotacje i jej parametry są rozwiązywane w czasie kompilacji. Mam następujący interfejs,

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

i inna klasa jako,

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

Oznaczam wiele klas adnotacją i chciałbym wiedzieć, czy mogę uniknąć określania ciągów w każdej adnotacji, której wolałbym zamiast tego użyć

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

Jednak powoduje to błędy kompilacji, takie jak wartość adnotacji powinna być inicjatorem tablicy itp. Czy ktoś wie, jak mogę użyć stałej String lub stałej String [], aby podać wartość do adnotacji?

Kannan Ekanath
źródło

Odpowiedzi:

127

Stałe kompilacji mogą być tylko prymitywami i ciągami znaków :

15.28. Wyrażenia stałe

Wyrażenie stałe czasu kompilacji to wyrażenie oznaczające wartość typu pierwotnego lub String, które nie kończy się nagle i składa się tylko z następujących elementów:

  • Literały typu pierwotnego i literały typu String
  • Rzuty na typy pierwotne i rzuty na typy String
  • [...] operatorzy [...]
  • Wyrażenia w nawiasach, których wyrażenie zawarte jest wyrażeniem stałym.
  • Proste nazwy, które odnoszą się do stałych zmiennych.
  • Kwalifikowane nazwy w postaci TypeName . Identyfikator odnoszący się do zmiennych stałych.

W rzeczywistości w Javie nie ma sposobu na ochronę elementów w tablicy. W czasie wykonywania ktoś zawsze może to zrobić FieldValues.FIELD1[0]="value3", dlatego tablica nie może być naprawdę stała, jeśli spojrzymy głębiej.

niepodważalny
źródło
14
Enum też! :) :)
TacB0sS
1
@ TacB0sS, wyliczenia nie są wyrażeniami stałymi.
jaco0646
Cóż ... może powinieneś spróbować i dać mi znać ... używam ich cały czas :)
TacB0sS
4
Bardziej odpowiednia specyfikacja znajduje się w sekcji Adnotacje . Oprócz wyrażenia stałego wartość adnotacji może być inicjatorem tablicy , literałem klasy lub stałą wyliczenia .
jaco0646
3
@ TacB0sS można używać enumw adnotacjach, ale nie są one stałymi w czasie kompilacji. Różnica staje się widoczna, gdy piszesz static final EnumType VARIABLE = EnumType.ENUM_CONSTANT;i próbujesz użyć VARIABLEw adnotacji; to nie zadziała. Możesz używać tylko tego, EnumType.ENUM_CONSTANTco nie jest wyrażeniem stałym, ale jest dozwolone w adnotacjach (i switchinstrukcjach).
Holger,
37

Możesz użyć stałej (tj. Statycznej, końcowej zmiennej) jako parametru adnotacji. Jako szybki przykład, dość często używam czegoś takiego:

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

Zwróć uwagę, że możliwe jest przekazanie TEST_TIMEOUTstałej bezpośrednio do adnotacji.

Z drugiej strony, nie przypominam sobie, że kiedykolwiek próbowałem tego z tablicą, więc możesz napotkać pewne problemy z niewielkimi różnicami w sposobie reprezentowania tablic jako parametrów adnotacji w porównaniu ze zmiennymi Java? Ale jeśli chodzi o drugą część twojego pytania, zdecydowanie możesz użyć stałego ciągu bez żadnych problemów.

EDIT: Właśnie próbowałem to z tablicy ciągów i nie napotkasz problem pan wspomniał - jednak kompilator nie mów mi, że „wartość atrybutu musi być stałe” mimo tablica jest określona jako public static final String[]. Może nie podoba mu się fakt, że tablice są zmienne? Hmm ...

Andrzej Doyle
źródło
1
Trudne dla mnie szczęście! O tak, udało mi się przekazać ciągi / liczby, ale nie tablice.
Spędzę
Tak, przypuszczam, że problemem jest tutaj zmienność tablicy FIELD1. Możesz zadeklarować tablicę za pomocą inicjatora tablicy, ponieważ nic innego nie może mieć dostępu do tej tablicy i nie można jej później zmienić.
ColinD
To rozwiązuje mój problem. Wystarczyło udostępnić stałą typu String między adnotacjami a kodem. Dzięki!
simon
1
statyczna zmienna końcowa nie jest jedynym warunkiem wstępnym. Jeśli spróbujesz dynamicznie obliczyć zmienną, otrzymasz ten sam komunikat o błędzie.
Wolfgang Fahl
11

W swoim przykładzie nie dostarczasz jej z tablicą. Następujące kompilacje dobrze:

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() {
    }
}
Steve B.
źródło
4
W przykładzie jest dostarczana z tablicą, ale nie taką, która jest tworzona bezpośrednio w deklaracji adnotacji.
ColinD,
7

Czy ktoś wie, jak mogę użyć stałej String lub stałej String [], aby podać wartość do adnotacji?

Niestety nie możesz tego zrobić z tablicami. W przypadku zmiennych niebędących tablicami wartość musi być ostateczną wartością statyczną.

Kevin
źródło
5

Myślę, że może to nie być możliwe w Javie, ponieważ adnotacje i jej parametry są rozwiązywane w czasie kompilacji.

Z Seam 2 http://seamframework.org/ można było rozwiązać parametry adnotacji w czasie wykonywania, używając języka wyrażeń w cudzysłowach.

W Seam 3 http://seamframework.org/Seam3/Solder ta funkcja to moduł Seam Solder

jorgwel
źródło
3
Nie, nie rozwiązałeś parametrów w czasie wykonywania. Parametr został rozwiązany w czasie kompilacji. Fakt, że zostały następnie użyte do zrobienia czegoś w czasie wykonywania, nie ma dosłownie nic wspólnego z ustawieniem ich wartości.
Załóż pozew Moniki
1

Możesz użyć wyliczenia i odnieść się do tego wyliczenia w polu adnotacji

Kaustubh Thawari
źródło
1
Powinieneś dodać przykład.
m02ph3u5