web-dev-qa-db-fra.com

Pourquoi n'est-il pas possible d'étendre les annotations en Java?

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.

Par exemple: je veux savoir si une annotation donnée est un validateur. Avec l'héritage, je pourrais naviguer par réflexe dans les super-classes pour savoir si cette annotation étend un ValidatorAnnotation. Sinon, comment puis-je y parvenir?

Alors, quelqu'un peut-il me donner une raison pour cette décision de conception?

219
sinuhepop

La réponse à la question JSR 175 Design, où il est dit:

Pourquoi ne supportez-vous pas le sous-typage des annotations (lorsqu'un type d'annotation en étend un autre)?

Cela complique le système de types d'annotation et rend beaucoup plus difficile l'écriture d '"outils spécifiques".

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

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

159
pedromarce

Les annotations extensibles ajouteraient effectivement la charge de la spécification et de la maintenance d'un autre système de types. Et ce serait un système de type assez unique, vous ne pouvez donc pas simplement appliquer un paradigme de type OO.

Réfléchissez à tous les problèmes lorsque vous introduisez un polymorphisme et un héritage dans une annotation (par exemple, que se passe-t-il lorsque la sous-annotation modifie les spécifications de méta-annotation telles que la rétention?)

Et toute cette complexité supplémentaire pour quel cas d'utilisation?

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

Essaye ça:

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

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

}

Comme vous pouvez le constater, vous pouvez facilement regrouper et catégoriser des annotations sans douleur inutile en utilisant les installations fournies.

Donc, KISS est la raison pour laquelle un système de type méta-type n’a pas été introduit dans le Java) langage.

[p.s. modifier]

J'ai utilisé le String simplement à des fins de 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. Notez que les valeurs sont entièrement fictives et à des fins de démonstration uniquement:

@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 {

}

66
alphazero

En un sens, vous l'avez déjà avec Annotations - meta Annotations. Si vous annotez une annotation avec des métadonnées, cela équivaut, à bien des égards, à l'extension d'une interface supplémentaire. Les annotations sont des interfaces, le polymorphisme n'entre donc pas en jeu. De par leur nature statique, il ne peut y avoir de dispatching dynamique à l'exécution.

Dans votre exemple de validateur, vous pouvez simplement obtenir sur l'annotation le type annoté et voir s'il possède une méta-annotation de validateur.

Le seul cas d'utilisation qui me soit utile est que l'héritage serait utile si vous vouliez pouvoir obtenir l'annotation par super-type, mais cela ajouterait toute une complexité, car une méthode ou un type donné peut comporter deux annotations de ce type, ce qui signifie qu'un tableau devrait être retourné au lieu d'un seul objet.

Je pense donc que la réponse ultime est que les cas d'utilisation sont ésotériques et compliquent les cas d'utilisation plus standard, ce qui en fait une valeur inutile.

11
Yishai

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

  1. Aucun sous-type d'annotations ne rend inutilement moche de nombreuses annotations complexes. On ne peut pas simplement avoir dans les annotations un attribut pouvant contenir l'une des trois choses suivantes. Vous devez avoir trois attributs distincts, ce qui déroute les développeurs et nécessite une validation à l'exécution pour garantir qu'un seul des trois est utilisé.

  2. Une seule annotation d'un type donné par site. Cela a conduit à un motif d'annotation de collection complètement inutile. @Validation et @Validations, @Image et @Images, etc.

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

5

J'ai peut-être trois ans de retard pour répondre à cette question, mais je l'ai trouvée intéressante parce que je me suis retrouvée au même endroit. Voici mon point de vue là-dessus. Vous pouvez afficher les annotations sous forme d'énums. Ils fournissent des informations à sens unique - utilisez-les ou perdez-les.

J'ai eu une situation où je voulais simuler GET, POST, PUT et DELETE dans une application web. Je voulais tellement avoir une "super" annotation appelée "HTTP_METHOD". Plus tard, j'ai compris que cela n'avait pas d'importance. Eh bien, je devais régler en utilisant un champ caché dans le formulaire HTML pour identifier DELETE et PUT (parce que POST et GET étaient disponibles de toute façon).

Sur le serveur, j'ai recherché un paramètre de requête masqué portant le nom "_method". Si la valeur était PUT ou DELETE, alors la méthode de requête HTTP associée était remplacée. Cela dit, peu importait si je devais étendre une annotation pour que le travail soit effectué. Toutes les annotations étaient identiques, mais elles étaient traitées différemment côté serveur.

Donc, dans votre cas, laissez tomber la démangeaison pour étendre les annotations. Traitez-les comme des "marqueurs". Ils "représentent" certaines informations, et pas nécessairement "manipulent" certaines informations.

2
mainas

Une chose à laquelle 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 peux me tromper :)

2
Janusz

Jamais pensé à ça mais ... semble que tu as 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 ça).

A propos de votre exemple avec 'validator' annotation - vous pouvez exploiter 'meta-annotation' alors. C'est à dire. vous appliquez une méta-annotation particulière à l'ensemble de l'interface d'annotation.

2
denis.zhdanov

le même problème que j'ai. Non, tu ne peux pas. Je me suis "discipliné" moi-même pour écrire les propriétés dans les annotations afin de respecter certaines normes. Ainsi, lorsque vous obtenez une annotation, vous pouvez "identifier" le type d'annotation od).

1
ante.sabo