Por que as classes java não herdam anotações de interfaces implementadas?

108

Tenho usado o AOP do Guice para interceptar algumas chamadas de método. Minha classe implementa uma interface e eu gostaria de anotar os métodos da interface para que o Guice pudesse selecionar os métodos corretos. Mesmo que o tipo de anotação seja anotado com a classe de implementação Inherited annotation, ela não herda a anotação conforme declarado no documento java de Inherited:

Observe também que esta meta-anotação apenas faz com que as anotações sejam herdadas das superclasses; as anotações nas interfaces implementadas não têm efeito.

Qual poderia ser o motivo disso? Conhecer todas as interfaces que uma classe de objeto implementa em tempo de execução não é tão difícil de fazer, portanto, deve haver um bom motivo para essa decisão.

Boris Pavlović
fonte

Respostas:

130

Eu diria que o motivo é que, caso contrário, ocorreria um problema de herança múltipla.

Exemplo:

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

Se eu fizer isso:

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

qual vai ser o resultado? 'baz', 'phleem' ou 'flopp'?


Por esse motivo, as anotações nas interfaces raramente são úteis.

Sean Patrick Floyd
fonte
9
as anotações nas interfaces só são úteis se você tiver uma estrutura que as suporte. BTW, neste exemplo getAnnotation () retorna null;)
Peter Lawrey
6
Eu não sei, pessoal. Nesse caso (se o erro de digitação não estivesse lá), esperaria um The field value is ambiguous.erro do compilador semelhante ao de duas interfaces declarando a mesma constante com valores diferentes. Eu sei que este não é um campo, mas os valores das anotações são todos resolvidos em tempo de compilação, não é? O recurso que estamos perdendo aqui seria muito útil em muitos casos. A propósito, desculpe por reviver um post antigo :).
Petr Janeček de
7
@Slanec dê uma olhada nos fontes do Spring para ver como os caras do Spring contornaram esses problemas. Consulte AnnotationUtils.findAnnotation (method, annotationType)
Sean Patrick Floyd
1
Eu estava pensando em escrever algo semelhante a isso. Com algum tipo de armazenamento em cache simples, esse parece um caminho a percorrer para mim. Obrigado! No exemplo acima, ele encontraria a Fooanotação de ( MyClassnão tem uma, então as interfaces são pesquisadas e obtidas na ordem em que estão depois implements) e, portanto, imprimirá "baz". Legal.
Petr Janeček de
2
@WChargin true, levou apenas 2 anos para alguém detectar aquele erro de digitação :-)
Sean Patrick Floyd
35

Do Javadoc para @Inherited:

Indica que um tipo de anotação é herdado automaticamente. Se uma meta-anotação herdada estiver presente em uma declaração de tipo de anotação e o usuário consultar o tipo de anotação em uma declaração de classe, e a declaração de classe não tiver nenhuma anotação para esse tipo, então a superclasse da classe será automaticamente consultada para o tipo de anotação. Este processo será repetido até que uma anotação para este tipo seja encontrada ou o topo da hierarquia de classes (Objeto) seja alcançado. Se nenhuma superclasse tiver uma anotação para esse tipo, a consulta indicará que a classe em questão não tem essa anotação. Observe que esse tipo de meta-anotação não tem efeito se o tipo anotado for usado para anotar qualquer coisa diferente de uma classe. Observe também que esta meta-anotação apenas faz com que as anotações sejam herdadas das superclasses;

Por outro lado, os validadores JSR 305 fazem algum tipo de pesquisa de herança. Se você tem uma hierarquia de classes:

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

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

Então as validações efetivas em Student.getAge()são @Nonnull @Min(5). @Nonnullnão tem @Inheritedmeta-anotação.

Eric Jablow
fonte
4
Esta deve ser a resposta selecionada
Andrzej Purtak
3
seu exemplo contradiz sua resposta, que diz que @Inheritednão tem efeito em nada além da classe
Oleg Mikheev
@ Herdado só funciona quando você usa a anotação na aula
Carlos Parker