¿Por qué las clases de Java no heredan las anotaciones de las interfaces implementadas?

108

He estado usando el AOP de Guice para interceptar algunas llamadas a métodos. Mi clase implementa una interfaz y me gustaría anotar los métodos de la interfaz para que Guice pueda seleccionar los métodos correctos. Incluso si el tipo de anotación está anotado con Anotación heredada , la clase de implementación no hereda la anotación como se indica en el documento java de Inherited:

Tenga en cuenta también que esta meta-anotación solo hace que las anotaciones se hereden de las superclases; las anotaciones en las interfaces implementadas no tienen ningún efecto.

¿Cuál podría ser la razón de ésto? Conocer todas las interfaces que implementa la clase de un objeto en tiempo de ejecución no es tan difícil de hacer, por lo que debe haber una buena razón detrás de esta decisión.

Boris Pavlović
fuente

Respuestas:

130

Yo diría que la razón es que, de lo contrario, se produciría un problema de herencia múltiple.

Ejemplo:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) @Inherited
public @interface Baz { String value(); }

public interface Foo{
    @Baz("baz") void doStuff();
}

public interface Bar{
    @Baz("phleem") void doStuff();
}

public class Flipp{
    @Baz("flopp") public void doStuff(){}
}

public class MyClass extends Flipp implements Foo, Bar{}

Si hago esto:

MyClass.class.getMethod("doStuff").getAnnotation(Baz.class).value()

¿cuál va a ser el resultado? ¿'baz', 'phleem' o 'flopp'?


Por esta razón, las anotaciones en las interfaces rara vez son útiles.

Sean Patrick Floyd
fuente
9
las anotaciones en las interfaces solo son útiles si tiene un marco que las admita. Por cierto, en este ejemplo getAnnotation () devuelve nulo;)
Peter Lawrey
6
No lo sé, gente. En este caso (si el error tipográfico no estaba allí), esperaría un The field value is ambiguous.error de compilador similar al de dos interfaces que declaran la misma constante con valores diferentes. Sé que esto no es un campo, pero los valores de anotación se resuelven todos en tiempo de compilación, ¿no es así? La función que nos falta aquí sería muy útil en muchos casos. Perdón por revivir una publicación anterior, por cierto :).
Petr Janeček
7
@Slanec echa un vistazo a la forma en que las fuentes de Spring para ver cómo los chicos de Spring solucionaron estos problemas. Consulte AnnotationUtils.findAnnotation (método, annotationType)
Sean Patrick Floyd
1
Estaba considerando escribir algo similar a esto. Con algún tipo de almacenamiento en caché simple, esto parece un camino a seguir para mí. ¡Gracias! En el ejemplo anterior, encontraría la Fooanotación 's ( MyClassno tiene una, entonces las interfaces se buscan y se toman en el orden en que están después implements) y por lo tanto imprimir "baz". Frio.
Petr Janeček
2
@WChargin es cierto, solo tomó 2 años para que alguien detectara ese error tipográfico :-)
Sean Patrick Floyd
35

Desde el Javadoc para @Inherited:

Indica que un tipo de anotación se hereda automáticamente. Si una meta-anotación heredada está presente en una declaración de tipo de anotación, y el usuario consulta el tipo de anotación en una declaración de clase, y la declaración de clase no tiene anotación para este tipo, entonces la superclase de la clase será consultada automáticamente para el tipo de anotación. Este proceso se repetirá hasta que se encuentre una anotación para este tipo o se alcance la parte superior de la jerarquía de clases (Objeto). Si ninguna superclase tiene una anotación para este tipo, la consulta indicará que la clase en cuestión no tiene dicha anotación. Tenga en cuenta que este tipo de meta-anotación no tiene ningún efecto si el tipo anotado se utiliza para anotar algo que no sea una clase. Tenga en cuenta también que esta meta-anotación solo hace que las anotaciones se hereden de las superclases;

Por otro lado, los validadores JSR 305 realizan algún tipo de búsqueda de herencia. Si tiene una jerarquía de clases:

//Person.java
@Nonnull
 public Integer getAge() {...}

//Student.java (inherits from Person)
@Min(5)
public Integer getAge() {...}

Entonces las validaciones efectivas Student.getAge()son @Nonnull @Min(5). @Nonnullno tiene @Inheritedmeta-anotación.

Eric Jablow
fuente
4
Esta debería ser la respuesta seleccionada
Andrzej Purtak
3
su ejemplo contradice su respuesta, que dice que @Inheritedno tiene ningún efecto en nada más que en la clase
Oleg Mikheev
@ Heredado solo funciona cuando usa la anotación en Clase
Carlos Parker