Why Java Classes Do Not Inherit Annotations from Implemented Interfaces

Why java classes do not inherit annotations from implemented interfaces?

I'd say the reason is that otherwise a multiple-inheritance problem would occur.

Example:

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

If I do this:

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

what's the result going to be? 'baz', 'phleem' or 'flopp'?


For this reason, annotations on interfaces are rarely useful.

Annotation is not inherited from interface method

From the javadocs of java.lang.annotation.Inherited:

Note that this meta-annotation type has no effect if the annotated
type is used to annotate anything other than a class. Note also that
this meta-annotation only causes annotations to be inherited from
superclasses; annotations on implemented interfaces have no effect.

Why can @Repeatable Annotations not be inherited from interfaces

Please recall the documentation of @Inherited:

If an Inherited meta-annotation is present on an annotation type declaration, and the user queries the annotation type on a class declaration, and the class declaration has no annotation for this type, then the class's superclass will automatically be queried for the annotation type.

In other words, @Inherited never was intended to be a feature for collecting multiple annotations on a type hierarchy. Instead, you will get the annotation of the most specific type which has an explicit annotation.

In other words, if you change your declaration to

@RepeatableAnnotation("FOO") @RepeatableAnnotation("BAR") class Base {}

@RepeatableAnnotation("C") @RepeatableAnnotation("D")
public class TestClass extends Base implements IntefaceA, IntefaceB {

it won’t change the result; FOO and BAR of Base are not inherited by TestClass as it has the explicit annotation values C and D.

Expanding this to the interface hierarchy would be awkward due to the multiple inheritance and the fact that a super-interface may turn out to be a sub-interface of another super-interface so finding the most specific one is not trivial. This differs heavily from the linear search of the superclass hierarchy.

You may encounter the situation where multiple unrelated annotated interfaces exist but it’s not clear why this ambiguity should be resolved by joining them into one repeated annotation. This would not harmonize with the behavior in all other scenarios.


Note that the answer you have linked is a bit odd as it shows code using a method annotation but method annotations are never inherited, regardless of whether you specified @Inherited or not (an audit tool should generate a warning when you combine @Target(ElementType.METHOD) with @Inherited, imho). @Inherited is relevant for type annotations only.

Is a type-level annotation always inherited by public methods of that type?

It is never the case that they are equivalent unless the library interpreting the annotation specifically decides to treat the type-level annotation as a default (e.g., Spring's @Transactional). Even then, it is entirely up to the code written in the library whether a combination of class-level and method-level annotations result in combination (@RequestMapping) or replacement (@Transactional) of definitions.

Do I Have to Put @Secured Annotations on Interface or on Class?

In your provided link said, @Transactional is also @Inherited. Lets break down each part of them.

As per spring's developers recommended that use @Transactional annotation with concrete class.
You can use @Transactional annotation in interface or a method inside the interface. You can think this will work as you expected if you used interface-based-proxies. Annotation that is not inherited refers that if you are using class-based-proxies then probably transaction attribute are not applied to that interface. So the ultimate object can not covered or wrapped by transactional attribute.

If so, @Secured annotation is @Inherited then this can be used both in interface and its implementation class.
From spring docs:

The Secured annotation is used to define a list of security configuration attributes for business methods.

For example:

 @Secured({ "ROLE_USER" })
public void create(Contact contact);

@Secured({ "ROLE_USER", "ROLE_ADMIN" })
public void update(Contact contact);

@Secured({ "ROLE_ADMIN" })
public void delete(Contact contact);

So In the bottom line, you may have multiple implementations for an interface. So, keeping your @Secured annotation in interface makes sense.

Perf4j does not profile annotated Interface method

Even if @Profiled used @Inherit it wouldn't work because inherited annotations are only ever passed on to sub classed and not implementations of interfaces.

@Inherited annotations are not inherited when used to annotate
anything other than a type. A type that implements one or more
interfaces never inherits any annotations from the interfaces it
implements.

Source: http://www.eclipse.org/aspectj/doc/released/adk15notebook/annotations.html#annotation-inheritance

More details: http://www.jroller.com/melix/entry/the_truth_about_annotations_inheritance

What would your custom processor do, query a service's interface for @Profiled? I suggest you manually annotate the service implementations because in my experience @Profiled is only helpful if you use it with its tag and message attributes (which differ in each implementing class I suppose).

http://perf4j.codehaus.org/devguide.html#Adding_the_Profiled_Annotation_to_Method_Declarations -> "@Profiled(tag = "dynamicTag_{$0}")"



Related Topics



Leave a reply



Submit