Dlaczego pojawia się błąd „Wartość atrybutu musi być stała”. Czy wartość null nie jest stała ???
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface SomeInterface {
Class<? extends Foo> bar() default null;// this doesn't compile
}
java
annotations
default
zrywak234
źródło
źródło
Class<? extends Foo> bar();
.Odpowiedzi:
Nie wiem dlaczego, ale JLS jest bardzo jasne:
Discussion Note that null is not a legal element value for any element type.
Definicja elementu domyślnego to:
DefaultValue: default ElementValue
Niestety, wciąż odkrywam, że nowe funkcje językowe (wyliczenia, a teraz adnotacje) mają bardzo nieprzydatne komunikaty o błędach kompilatora, gdy nie spełniają one specyfikacji języka.
EDYCJA: Trochę googleing znalazło następujące w JSR-308, gdzie argumentują za dopuszczeniem wartości null w tej sytuacji:
Myślę, że tylko dwa ostatnie punkty są istotne dla „dlaczego nie zrobić tego w pierwszej kolejności”. Ostatni punkt z pewnością prowadzi do dobrego punktu - procesor adnotacji nigdy nie musi się martwić, że otrzyma wartość null w wartości adnotacji. Zwykle postrzegam to jako bardziej zadanie procesorów adnotacji i innego takiego kodu ramowego, aby wykonać tego rodzaju sprawdzenie, aby kod programistów był bardziej przejrzysty niż na odwrót, ale z pewnością utrudniłoby to uzasadnienie zmiany.
źródło
Spróbuj tego
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface SomeInterface { Class bar() default void.class; }
Nie wymaga nowej klasy i jest już słowem kluczowym w Javie, które nic nie znaczy.
źródło
Class<? extends Foo> bar() default void.null
nie kompiluje się.Wydawałoby się, że jest to nielegalne, chociaż JLS jest w tym bardzo niejasny.
Zerwałem pamięć, aby spróbować pomyśleć o istniejącej adnotacji, która miała atrybut Class do adnotacji, i zapamiętałem tę z interfejsu API JAXB:
@Retention(RUNTIME) @Target({PACKAGE,FIELD,METHOD,TYPE,PARAMETER}) public @interface XmlJavaTypeAdapter { Class type() default DEFAULT.class; static final class DEFAULT {} }
Możesz zobaczyć, jak musieli zdefiniować fikcyjną klasę statyczną, aby przechowywać odpowiednik wartości null.
Nieprzyjemny.
źródło
Wygląda na to, że jest na to inny sposób.
To też mi się nie podoba, ale może zadziałać.
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface SomeInterface { Class<? extends Foo>[] bar() default {}; }
Więc w zasadzie zamiast tego tworzysz pustą tablicę. Wydaje się, że zezwala na wartość domyślną.
źródło
Jak wspomniano, specyfikacja języka Java nie zezwala na wartości null w domyślnych wartościach adnotacji.
To, co zwykle robię, to definiowanie
DEFAULT_VALUE
stałych u góry definicji adnotacji. Coś jak:public @interface MyAnnotation { public static final String DEFAULT_PREFIX = "__class-name-here__ default"; ... public String prefix() default DEFAULT_PREFIX; }
Następnie w swoim kodzie robię coś takiego:
if (myAnnotation.prefix().equals(MyAnnotation.DEFAULT_PREFIX)) { ... }
W twoim przypadku z klasą zdefiniowałbym po prostu klasę markera. Niestety nie możesz mieć dla tego stałej, więc zamiast tego musisz zrobić coś takiego:
public @interface MyAnnotation { public static Class<? extends Foo> DEFAULT_BAR = DefaultBar.class; ... Class<? extends Foo> bar() default DEFAULT_BAR; }
Twoja
DefaultFoo
klasa byłaby po prostu pustą implementacją, aby kod mógł:if (myAnnotation.bar() == MyAnnotation.DEFAULT_BAR) { ... }
Mam nadzieję że to pomoże.
źródło
.equals()
a nie==
@Doradus? Czy otrzymałeś inną wartość lub inny przedmiot.==
..equals()
. Zaskakujący.Ten komunikat o błędzie jest mylący, ale nie,
null
literał nie jest wyrażeniem stałym, zgodnie z definicją w specyfikacji języka Java, tutaj .Co więcej, specyfikacja języka Java mówi
I wyjaśnić, co to oznacza
Więc tutaj twój typ elementu
Class<? extends Foo>
nie jest współmierny z wartością domyślną, ponieważ ta wartość tonull
.źródło
or
i wewnętrzneand
, których nie można pominąć.Jak powiedzieli inni, istnieje reguła, która mówi, że null nie jest prawidłową wartością domyślną w Javie.
Jeśli masz ograniczoną liczbę możliwych wartości, które może mieć pole , jedną z opcji obejścia tego problemu jest ustawienie typu pola jako niestandardowego wyliczenia, które samo zawiera mapowanie na null. Na przykład wyobraź sobie, że mam następującą adnotację, dla której chcę domyślnej wartości null:
public @interface MyAnnotation { Class<?> value() default null; }
Jak ustaliliśmy, jest to niedozwolone. Zamiast tego możemy zdefiniować wyliczenie:
public enum MyClassEnum { NULL(null), MY_CLASS1(MyClass1.class), MY_CLASS2(MyClass2.class), ; public final Class<?> myClass; MyClassEnum(Class<?> aClass) { myClass = aClass; } }
i zmień adnotację jako taką:
public @interface MyAnnotation { MyClassEnum value() default MyClassEnum.NULL; }
Główną wadą tego (oprócz konieczności wyliczenia możliwych wartości) jest to, że teraz opakowałeś swoją wartość w wyliczenie, więc musisz wywołać właściwość / getter na wyliczeniu, aby uzyskać wartość.
źródło