2009-10-26 22 views
194

Nie rozumiem, dlaczego nie ma dziedziczenia adnotacji Java, podobnie jak klasy Java. Myślę, że byłoby to bardzo przydatne.Dlaczego nie można rozszerzyć adnotacji w Javie?

Na przykład: Chcę się dowiedzieć, czy dana adnotacja jest walidatorem. Dzięki dziedziczeniu mogę odruchowo poruszać się w klasach nadrzędnych, aby dowiedzieć się, czy ta adnotacja rozciąga się na ValidatorAnnotation. W przeciwnym razie, jak mogę to osiągnąć?

Czy ktoś może podać mi uzasadnienie tej decyzji projektowej?

+1

Uwaga, BTW, że wszystkie adnotacje rozszerzają "java.lang.annotation.Annotation", tj. Każda adnotacja to 'instanceof', chociaż ten fakt nie jest jawnie zadeklarowany. –

Odpowiedz

148

o powód, dlaczego nie został zaprojektowany w ten sposób można znaleźć odpowiedź w JSR 175 projektowania FAQ, gdzie mówi:

Dlaczego nie wspierać adnotacji Subtyping (gdzie rozciąga się jeden typ adnotacji inne)?

To komplikuje system opisów o typie i sprawia, że ​​trudno jest napisać "Szczegółowe narzędzia".

...

„specyficzny” Narzędzia - Programy tego zapytania znane typy adnotacji arbitralnych programów zewnętrznych. Generatory szczebli, na przykład , należą do tej kategorii. Programy te będą czytać opatrzone przypisami klasy bez wczytywania ich do maszyny wirtualnej , ale będą ładować interfejsy adnotacji .

Tak, tak, myślę, że powodem jest po prostu KISS. W każdym razie wydaje się, że ten problem (wraz z wieloma innymi) jest analizowany jako część JSR 308, a można nawet znaleźć alternatywny kompilator z tą funkcjonalnością opracowaną już przez Mathias Ricken.

+61

No cóż, może jestem głupi, ale myślę, że szkoda nie może rozszerzać adnotacji tylko po to, by "zachować prostotę". Przynajmniej projektanci Javy nie myśleli tak samo o dziedziczeniu klas: P – sinuhepop

+5

Podobno [planowane na Java 8] (http://openjdk.java.net/jeps/104) – assylias

+2

Java 8 M7, nie wydaje się wsparciem adnotacje klasy. Jaka szkoda. – Ceki

1

ten sam problem, który mam. Nie, nie możesz. "Zdyscyplinowałem" siebie, aby pisać właściwości w adnotacjach, aby szanować niektóre standardy, więc na zewnątrz, kiedy dostaniesz adnotację, możesz "powąchać", jakie to adnotacje na podstawie posiadanych właściwości.

1

Jedną z rzeczy, o których mogłem pomyśleć, jest możliwość posiadania wielu adnotacji. Możesz więc dodać weryfikator i dokładniejszą adnotację w tym samym miejscu. Ale mógłbym się mylić :)

2

Nigdy o tym nie myślałem, ale ... wydaje się, że masz rację, nie ma problemu z funkcją dziedziczenia adnotacji (przynajmniej nie widzę z tym problemu).

O swojej przykład „weryfikatorów” adnotacji - można wykorzystać „meta-adnotacji” podejście wtedy. To znaczy. stosuje się meta-adnotacje do całego interfejsu adnotacji.

+0

Być może trzy lata spóźniłem się na odpowiedź na to pytanie, ale uznałem to za interesujące, ponieważ znalazłem się w tym samym miejscu. – mainas

62

Rozszerzalne adnotacje spowodowałyby dodatkowe obciążenie związane z określeniem i utrzymaniem innego systemu typów. Byłby to dość unikalny system typów, więc nie można po prostu zastosować paradygmatu typu OO.

Pomyśl przez wszystkie kwestie, gdy wprowadzi polimorfizm i dziedziczenie do adnotacji (na przykład, co się dzieje, gdy sub-adnotacja zmienia specyfikację meta-adnotacji, takich jak zatrzymywanie?)

A wszystko to dodane złożoność za to, co użytkowej przypadku ?

Chcesz się dowiedzieć, czy dana adnotacja należy do kategorii?

Spróbuj tego:

@Target(ElementType.ANNOTATION_TYPE) 
public @interface Category { 
    String category(); 
} 

@Category(category="validator") 
public @interface MyFooBarValidator { 

} 

Jak widać, można łatwo grupę i kategoryzować adnotacje bez zbędnego bólu za pomocą dostarczonego udogodnienia.

Tak więc, KISS jest powodem niewprowadzania systemu typu meta do języka Java.

[p.s. edytuj]

Użyłem Stringa po prostu dla demonstracji iz uwagi na metatag otwarty meta. W przypadku danego projektu można oczywiście użyć wyliczenia kategorii i określić wiele kategorii ("dziedziczenie wielokrotne") do danej adnotacji. Należy pamiętać, że wartości te są całkowicie fałszywe i wyłącznie w celach demonstracyjnych:

@Target(ElementType.ANNOTATION_TYPE) 
public @interface Category { 
    AnnotationCategory[] category(); 
} 
public enum AnnotationCategory { 
    GENERAL, 
    SEMANTICS, 
    VALIDATION, 
    ETC 
} 

@Category(category={AnnotationCategory.GENERAL, AnnotationCategory.SEMANTICS}) 
public @interface FooBarAnnotation { 

} 

+0

Nie działa wydrukuje fałsz: '@Target (ElementType.ANNOTATION_TYPE) @Retention (RetentionPolicy.RUNTIME) @ interfejs C {}; @Target (ElementType.METHOD) @Retention (RetentionPolicy.RUNTIME) @C @interface publiczny K {} klasy A { @F void S() {} } @ Test public void blahTest() wyrzuca wyjątek NoSuchMethodException { Metoda m = a.class.getMethod ("S"); System.out.println (m.isAnnotationPresent (C.class)); } ' – user1615664

+0

Adnotujemy adnotację. a # S ma adnotację F. Samo F. ​​jest opatrzone adnotacją C. Spróbuj tego. – alphazero

+0

Tak, to prawda. Ale czy istnieje sposób, aby zrobić to bardziej czyściutko, zamiast czytać za pośrednictwem proxy Adnotacji? – user1615664

10

W pewnym sensie już masz go z adnotacjami - meta adnotacji. Jeśli dodasz adnotację do meta-informacji, jest to na wiele sposobów równoznaczne z rozszerzeniem dodatkowego interfejsu.Adnotacje są interfejsami, więc polimorfizm tak naprawdę nie wchodzi w grę, a ponieważ mają one charakter statyczny, nie może istnieć dynamiczna wysyłka środowiska wykonawczego.

W przykładzie walidatora można po prostu na adnotacji uzyskać typ adnotacji i sprawdzić, czy ma meta-adnotację weryfikatora.

Jedyny przypadek użycia, który mogłem zobaczyć, to, że dziedziczenie pomogłoby, gdybyś chciał uzyskać adnotację przez supertyp, ale to by wniosło całą masę złożoności, ponieważ dana metoda lub typ może mieć dwa takie adnotacje na nim, co oznacza, że ​​tablica musiałaby zostać zwrócona zamiast tylko jednego obiektu.

Więc myślę, że ostateczna odpowiedź jest taka, że ​​przypadki użycia są ezoteryczne i komplikują bardziej standardowe przypadki użycia, co sprawia, że ​​nie warto.

1

Być może trzy lata spóźniłem się na udzielenie odpowiedzi na to pytanie, ale uznałem to za interesujące, ponieważ znalazłem się w tym samym miejscu. Oto moje podejście do tego. Możesz wyświetlać adnotacje jako wyliczenia. Zapewniają one jednokierunkowy rodzaj informacji - wykorzystuj ją lub gub ją.

Miałem sytuację, w której chciałem symulować GET, POST, PUT i DELETE w aplikacji internetowej. Tak bardzo chciałem mieć "super" adnotację o nazwie "HTTP_METHOD". Później uświadomiłem sobie, że to nie ma znaczenia. Cóż, musiałem zadowolić się użyciem ukrytego pola w formularzu HTML, aby zidentyfikować DELETE i PUT (ponieważ i tak POST i GET były dostępne).

Po stronie serwera szukałem ukrytego parametru żądania o nazwie "_method". Jeśli wartość to PUT lub DELETE, to przesłoniła powiązaną z nią metodę żądania HTTP. Powiedziawszy to, nie miało znaczenia, czy muszę przedłużyć adnotację, aby wykonać pracę. Wszystkie adnotacje wyglądały tak samo, ale były traktowane inaczej po stronie serwera.

W takim przypadku upuść swędzenie, aby rozszerzyć adnotacje. Traktuj je jak "markery". "Przedstawiają" pewne informacje i niekoniecznie "manipulują" niektórymi informacjami.

2

Projektanci obsługi adnotacji Java dokonali szeregu "uproszczeń" ze szkodą dla społeczności Java.

  1. Brak podtytułów adnotacji sprawia, że ​​wiele złożonych adnotacji jest niepotrzebnie brzydka. Nie można po prostu mieć atrybutu w adnotacjach, które mogą pomieścić jedną z trzech rzeczy. Trzeba mieć trzy oddzielne atrybuty, co dezorientuje programistów i wymaga sprawdzania w czasie wykonywania, aby zapewnić, że tylko jedna z trzech jest używana.

  2. Tylko jedna adnotacja danego typu na witrynę. Doprowadziło to do zupełnie niepotrzebnego wzorca adnotacji kolekcji. @Validation i @Validations, @Image i @Images itp

Drugi jest naprawione w Java 8, ale jest już za późno. Wiele frameworków zostało napisanych w oparciu o to, co było możliwe w Javie 5, a teraz te brodawki API pozostają tutaj przez długi czas.

+0

Co więcej, uniemożliwia to również zdefiniowanie właściwości, które mają rekursywnie zagnieżdżone atrybuty - co jest obsługiwane przez schemat XML. Dzięki temu adnotacje są mniej wydajne niż XML – user2833557

Powiązane problemy