2009-10-26 10 views
194

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 qué no es posible extender anotaciones en Java?

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 se extiende a ValidatorAnnotation. De lo contrario, ¿cómo puedo lograr esto?

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

+1

Nota, por cierto, que todas las anotaciones se extienden 'java.lang.annotation.Annotation', es decir, cualquier anotación es' instanceof' aunque este hecho no se declara explícitamente. –

Respuesta

148

Sobre la razón por la que no fue diseñado de esa manera se puede encontrar la respuesta en el JSR 175 Diseño FAQ, donde dice:

¿Por qué no soportan subtipos de anotación (los que un tipo de anotación se extiende otro)?

Complica el tipo de anotación sistema, y ​​lo hace mucho más difícil de escribir "Herramientas específicas".

...

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

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

+61

Bueno, tal vez soy estúpido, pero creo que es una pena no extender anotaciones solo para "mantenerlo simple". Al menos, los diseñadores de Java no pensaban lo mismo sobre la herencia de clase: P – sinuhepop

+5

Aparentemente [planeado para Java 8] (http://openjdk.java.net/jeps/104) – assylias

+2

Java 8 M7, no parece compatible con clasificando anotaciones. Qué pena. – Ceki

1

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.

1

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 :)

2

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).

Sobre su ejemplo, con 'validador' anotación - se puede explotar 'meta-anotación' enfoque a continuación. Es decir. aplica meta-anotación particular a toda la interfaz de anotación.

+0

Podría estar tres años tarde respondiendo a esta pregunta, pero me pareció interesante porque me encontré en el mismo lugar. – mainas

62

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.

pensar en todas las cuestiones cuando se introduce el polimorfismo y la herencia a una anotación (por ejemplo, lo que ocurre cuando sub-anotación cambia especificaciones técnicas meta-anotaciones tales como la retención?)

Y todo esto añade complejidad a lo de casos de uso ?

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

Prueba esto:

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

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

} 

Como se puede ver, usted puede fácilmente grupo y clasificar las anotaciones sin dolor indebido utilizando las instalaciones previstas.

Por lo tanto, KISS es la razón por la que no se introduce un sistema de tipos de meta-tipo al lenguaje Java.

[p.s. editar]

Utilicé la cadena 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. Ten en cuenta que los valores son totalmente falsas y sólo 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 { 

} 

+0

Does Not Work se imprimirá falso: '@Target (ElementType.ANNOTATION_TYPE) @Retention (RetentionPolicy.RUNTIME) @interface C {}; @Target (ElementType.METHOD) @Retention (RetentionPolicy.RUNTIME) @interface pública @C F} { class A { @F public void S() {}} @ Prueba public void blahTest() arroja NoSuchMethodException { Método m = a.class.getMethod ("S"); System.out.println (m.isAnnotationPresent (C.class)); } ' – user1615664

+0

Anotamos una anotación. a # S tiene la anotación F. F es anotada por C. Inténtalo. – alphazero

+0

Sí, eso es correcto. Pero, ¿hay alguna manera de hacerlo de forma más limpia en lugar de leer el proxy de anotación? – user1615664

10

En un sentido ya lo tienes con Anotaciones - Anotaciones meta. 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 polimorfismo no entra realmente en juego, y dado que son de naturaleza estática, no puede haber despacho dinámico 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 quisiera 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 en él, 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.

1

Podría estar tres años tarde respondiendo 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.

Por lo tanto, en su caso, elimine el picor para ampliar las anotaciones. Trátelos como 'marcadores'. Ellos "representan" cierta información, y no necesariamente "manipulan" cierta información.

2

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

  1. Sin subtítulos de anotaciones 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 determinado por sitio. Esto ha llevado al patrón de anotación de colección completamente innecesario. @Validation y @Validations, @image y @Images, etc.

La segunda es que se subsanen 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.

+0

No solo eso, también hace que sea imposible definir las propiedades que tienen atributos anidados recursivamente, que es compatible con el esquema XML. Esto hace que las anotaciones sean estrictamente menos poderosas que XML – user2833557

Cuestiones relacionadas