2009-10-26 3 views
194

Je ne comprends pas pourquoi il n'y a pas d'héritage dans les annotations Java, tout comme les classes Java. Je pense que ce serait très utile.Pourquoi n'est-il pas possible d'étendre les annotations en Java?

Par exemple: Je veux savoir si une annotation donnée est un validateur. Avec l'héritage, je pourrais naviguer par réflexe à travers les superclasses pour savoir si cette annotation étend un ValidatorAnnotation. Sinon, comment puis-je y parvenir? Donc, quelqu'un peut-il me donner une raison pour cette décision de conception?

+1

Notez, BTW, que toutes les annotations étendent 'java.lang.annotation.Annotation', c'est-à-dire que toute annotation est' instanceof' bien que ce fait ne soit pas explicitement déclaré. –

Répondre

148

A propos de la raison pour laquelle il n'a pas été conçu de cette façon vous pouvez trouver la réponse dans la FAQ conception JSR 175, où il est dit:

Pourquoi ne vous prend pas en charge l'annotation sous-typage (où un type d'annotation étend un autre)?

Il complique le système d'annotation de type , et rend beaucoup plus difficile à écrire "Outils Spécifiques" .

...

« Outils spécifiques » - programmes qui interrogent types d'annotation connus arbitraires programmes externes. Les générateurs de tronçons, par exemple, entrent dans cette catégorie. Ces programmes liront les classes annotées sans les charger dans la machine virtuelle , mais chargeront les interfaces d'annotation .

Donc, oui je suppose, la raison en est que c'est juste KISS. Quoi qu'il en soit, il semble que ce problème (avec beaucoup d'autres) est examiné dans le cadre de JSR 308, et vous pouvez même trouver un compilateur alternatif avec cette fonctionnalité déjà développé par Mathias Ricken.

+61

Eh bien, peut-être que je suis stupide, mais je pense que c'est dommage ne peut pas étendre les annotations juste pour "garder les choses simples". Au moins, les concepteurs de Java ne pensaient pas la même chose à propos de l'héritage de classe: P – sinuhepop

+5

Apparemment [prévu pour Java 8] (http://openjdk.java.net/jeps/104) – assylias

+2

Java 8 M7, ne semble pas support sous-classe classer les annotations. Quel dommage. – Ceki

1

le même problème que j'ai. Non, tu ne peux pas. Je me suis «discipliné» moi-même pour écrire des propriétés dans des annotations afin de respecter certaines normes, donc à l'extérieur lorsque vous obtenez des annotations, vous pouvez «renifler» quelle sorte d'annotation elle est par propriétés.

1

Une chose que je pourrais penser est la possibilité d'avoir plusieurs annotations. Vous pouvez donc ajouter un validateur et une annotation plus spécifique au même endroit. Mais je pourrais me tromper :)

2

N'a jamais pensé à cela mais ... semble que vous avez raison, il n'y a pas de problème avec la facilité d'héritage des annotations (au moins je ne vois pas le problème avec elle).

A propos de votre exemple avec 'validateur' annotation - vous pouvez exploiter l'approche 'méta-annotation' alors. C'est à dire. vous appliquez des méta-annotations particulières à toute l'interface d'annotation.

+0

Je pourrais avoir trois ans de retard pour répondre à cette question, mais je l'ai trouvé intéressant parce que je me suis retrouvé au même endroit. – mainas

62

Les annotations extensibles ajouteraient effectivement la charge de spécifier et de maintenir un autre type de système. Et ce serait un système de type assez unique, donc vous ne pourriez pas simplement appliquer un paradigme de type OO.

Pensez à tous les problèmes lorsque vous présentez polymorphisme et héritage à une annotation (par exemple ce qui se passe lorsque la sous-annotation change caractéristiques méta-annotations telles que la rétention?)

Et tout cela ajouté à la complexité de ce cas d'utilisation ?

Vous souhaitez savoir si une annotation donnée appartient à une catégorie?

Essayez ceci:

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

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

} 

Comme vous pouvez le voir, vous pouvez facilement classer groupe et annotations sans douleur excessive à l'aide des équipements fournis. Donc, KISS est la raison de ne pas introduire un système de type méta-type au langage Java.

[p.s. edit]

J'ai utilisé la chaîne simplement pour la démonstration et en vue d'une méta-annotation ouverte. Pour votre propre projet, vous pouvez évidemment utiliser une énumération de types de catégories et spécifier plusieurs catégories («héritage multiple») pour une annotation donnée. Prenez note que les valeurs sont tout à fait faux et uniquement à des fins de démonstration:

@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

Ne fonctionne pas affichera false: '@Target (ElementType.ANNOTATION_TYPE) @Retention (RetentionPolicy.RUNTIME) @interface C {}; @Target (ElementType.METHOD) @Retention (RetentionPolicy.RUNTIME) @interface publique @C F {} class a {public void @F S() {}} @ Test public void blahTest() throws NoSuchMethodException { Méthode m = a.class.getMethod ("S"); System.out.println (m.isAnnotationPresent (C.class)); } ' – user1615664

+0

Nous annotons une annotation. un # S a une annotation F. F lui-même est annoté par C. Essayez cela. – alphazero

+0

Oui, c'est correct. Mais existe-t-il un moyen de le faire plus proprement plutôt que de lire le proxy Annotation? – user1615664

10

Dans un sens, vous avez déjà avec annotations - méta annotations. Si vous annotez une annotation avec des méta-informations, cela équivaut à bien des égards à étendre une interface supplémentaire.Les annotations sont des interfaces, donc le polymorphisme n'intervient pas vraiment, et comme elles sont statiques, il n'y a pas de répartition dynamique à l'exécution.

Dans votre exemple de validateur, vous pouvez simplement obtenir sur l'annotation le type annoté et voir s'il contient une méta-annotation de validateur. Le seul cas d'utilisation que je pourrais voir que l'héritage aiderait est si vous vouliez être capable d'obtenir l'annotation par super type, mais cela ajouterait tout un tas de complexité, parce qu'une méthode ou un type donné peut en avoir deux annotations sur elle, ce qui signifie qu'un tableau devrait être retourné au lieu d'un seul objet. Donc, je pense que la réponse ultime est que les cas d'utilisation sont ésotériques et compliquent davantage les cas d'utilisation standard, ce qui ne vaut pas la peine.

1

Je pourrais avoir trois ans de retard pour répondre à cette question, mais je l'ai trouvé intéressant parce que je me suis retrouvé au même endroit. Voici mon point de vue. Vous pouvez afficher les annotations sous forme d'énumérations. Ils fournissent un type d'information à sens unique - utilisez-le ou perdez-le.

J'avais une situation où je voulais simuler GET, POST, PUT et DELETE dans une application web. Je voulais tellement avoir une "super" annotation qui s'appelait "HTTP_METHOD". Plus tard, j'ai compris que cela n'avait pas d'importance. Eh bien, j'ai dû me contenter d'utiliser un champ caché dans le formulaire HTML pour identifier DELETE et PUT (parce que POST et GET étaient disponibles de toute façon).

Du côté serveur, j'ai recherché un paramètre de requête caché avec le nom "_method". Si la valeur était PUT ou DELETE, elle a remplacé la méthode de requête HTTP associée. Cela dit, peu importe si j'avais besoin d'une annotation pour faire le travail. Toutes les annotations semblaient identiques, mais elles étaient traitées différemment côté serveur.

Dans votre cas, supprimez les démangeaisons pour étendre les annotations. Traitez-les comme des «marqueurs». Ils "représentent" certaines informations et ne "manipulent" pas nécessairement certaines informations.

2

Les concepteurs du support des annotations Java ont fait un certain nombre de "simplifications" au détriment de la communauté Java.

  1. Aucun sous-type d'annotation ne rend inutiles de nombreuses annotations complexes. On ne peut pas simplement avoir un attribut dans une annotation qui peut contenir l'une des trois choses. Il faut avoir trois attributs distincts, ce qui désoriente les développeurs et nécessite une validation à l'exécution pour s'assurer que seul l'un des trois est utilisé.

  2. Une seule annotation d'un type donné par site. Cela a conduit au modèle d'annotation de collection totalement inutile. @Validation et @Validations, @image et @Images, etc.

Le second est en cours en Java 8 corrigées, mais il est trop tard. De nombreux frameworks ont été écrits sur la base de ce qui était possible dans Java 5 et maintenant ces verrues API sont là pour durer longtemps.

+0

Non seulement cela, mais il est également impossible de définir des propriétés qui ont des attributs imbriqués récursivement - ce qui est pris en charge par le schéma XML. Cela rend les annotations strictement moins puissantes que XML – user2833557

Questions connexes