¿Por qué no es posible extender anotaciones en Java?

No entiendo por qué no hay herencia en las anotaciones de Java, al igual que las clases de Java. Creo que sería muy útil.

Por ejemplo: quiero saber si una anotación determinada es un validador. Con la herencia, podría navegar reflexivamente a través de las superclases para saber si esta anotación extiende una ValidatorAnnotation . De lo contrario, ¿cómo puedo lograr esto?

Entonces, ¿alguien puede darme una razón para esta decisión de diseño?

Sobre el motivo por el cual no fue diseñado de esa manera, puede encontrar la respuesta en las Preguntas frecuentes sobre el diseño de JSR 175 , donde dice:

¿Por qué no admite la subtipificación de anotaciones (donde un tipo de anotación se extiende a otro)?

Esto complica el sistema de tipo de anotación y hace que sea mucho más difícil escribir “Herramientas específicas”.

“Herramientas específicas”: progtwigs que consultan tipos de anotación conocidos de progtwigs externos arbitrarios. Los generadores de código auxiliar, por ejemplo, entran en esta categoría. Estos progtwigs leerán las clases anotadas sin cargarlas en la máquina virtual, pero cargarán las interfaces de anotación.

Entonces, sí, supongo, la razón es que solo KISS. De todos modos, parece que este problema (junto con muchos otros) se está investigando como parte de JSR 308 , e incluso se puede encontrar un comstackdor alternativo con esta funcionalidad ya desarrollada por Mathias Ricken .

Las anotaciones extensibles agregarían efectivamente la carga de especificar y mantener otro tipo de sistema. Y este sería un sistema de tipo bastante único, por lo que no podría simplemente aplicar un paradigma tipo OO.

Piensa en todos los problemas cuando introduzcas el polymorphism y la herencia en una anotación (por ejemplo, ¿qué ocurre cuando la subanotación cambia las especificaciones de la metaanotación, como la retención?)

Y toda esta complejidad añadida para qué caso de uso?

¿Desea saber si una anotación determinada pertenece a una categoría?

Prueba esto:

 @Target(ElementType.ANNOTATION_TYPE) public @interface Category { String category(); } @Category(category="validator") public @interface MyFooBarValidator { } 

Como puede ver, puede agrupar y clasificar anotaciones fácilmente sin dolor excesivo utilizando las instalaciones proporcionadas.

Entonces, KISS es la razón por la cual no se introduce un sistema de tipo meta-tipo al lenguaje Java.

[ps edit]

Utilicé el String simplemente para la demostración y en vista de una metaanotación de final abierto. Para su propio proyecto dado, obviamente puede usar una enumeración de tipos de categorías y especificar múltiples categorías (“herencia múltiple”) para una anotación dada. Tenga en cuenta que los valores son completamente falsos y solo para fines de demostración:

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

En cierto sentido, ya lo tienes con Anotaciones: meta anotaciones. Si anota una anotación con metainformación, eso es en muchos sentidos equivalente a extender una interfaz adicional. Las anotaciones son interfaces, por lo que el polymorphism no entra realmente en juego, y dado que son de naturaleza estática, no puede haber despacho dynamic en tiempo de ejecución.

En su ejemplo de validador, podría simplemente en la anotación obtener el tipo anotado y ver si tiene una meta-anotación de validador.

El único caso de uso que pude ver es que la herencia ayudaría si quisieras obtener la anotación por supertipo, pero eso agregaría un montón de complejidad, porque un método o tipo determinado puede tener dos anotaciones así, lo que significa que se debería devolver una matriz en lugar de solo un objeto.

Así que creo que la respuesta final es que los casos de uso son esotéricos y complican más casos de uso estándar por lo que no vale la pena.

Los diseñadores de soporte de anotación de Java realizaron una serie de “simplificaciones” en detrimento de la comunidad de Java.

  1. Ningún subtipo de anotación hace que muchas anotaciones complejas sean innecesariamente feas. Uno no puede simplemente tener un atributo dentro de una anotación que pueda contener una de tres cosas. Uno necesita tener tres atributos separados, lo que confunde a los desarrolladores y requiere validación en tiempo de ejecución para garantizar que solo se use uno de los tres.

  2. Solo una anotación de un tipo dado por sitio. Esto ha llevado al patrón de anotación de colección completamente innecesario. @Validation y @Validations, @Image e @Images, etc.

El segundo está siendo remediado en Java 8, pero es demasiado tarde. Se han escrito muchos frameworks basados ​​en lo que era posible en Java 5 y ahora estas verrugas de API están aquí para quedarse por mucho tiempo.

Nunca pensé en eso pero … parece que tienes razón, no hay ningún problema con el recurso de herencia de anotaciones (al menos no veo el problema con él).

Acerca de su ejemplo con la anotación “validador” : puede aprovechar el enfoque de “meta-anotación” . Es decir, aplica meta-anotación particular a toda la interfaz de anotación.

el mismo problema que tengo No, no puedes. Me “discipliné” a mí mismo para escribir propiedades en anotaciones para respetar algunas normas, por lo tanto, cuando obtienes una anotación, puedes “olfatear” qué tipo de anotación od es por las propiedades que tiene.

Una cosa que podría pensar es la posibilidad de tener múltiples anotaciones. De modo que podría agregar un validador y una anotación más específica en el mismo lugar. Pero podría estar equivocado 🙂

Puede que tarde tres años en responder a esta pregunta, pero me pareció interesante porque me encontré en el mismo lugar. Aquí está mi opinión sobre esto. Puede ver las anotaciones como enumeraciones. Brindan un tipo de información de sentido único: úselo o piérdalo.

Tuve una situación en la que quería simular GET, POST, PUT y DELETE en una aplicación web. Tenía tantas ganas de tener una anotación “super” que se llamaba “HTTP_METHOD”. Más tarde me di cuenta de que no importaba. Bueno, tuve que conformarme con usar un campo oculto en el formulario HTML para identificar DELETE y PUT (porque POST y GET estaban disponibles de todos modos).

En el lado del servidor, busqué un parámetro de solicitud oculto con el nombre, “_method”. Si el valor fue PUT o DELETE, anula el método de solicitud HTTP asociado. Habiendo dicho eso, no importaba si necesitaba o no extender una anotación para hacer el trabajo. Todas las anotaciones parecían iguales, pero se trataron de manera diferente en el lado del servidor.

Entonces, en tu caso, abandona la picadura para extender las anotaciones. Trátelos como ‘marcadores’. Ellos “representan” cierta información, y no necesariamente “manipulan” cierta información.