Why Java Annotations Don't Inherit to Subclass Methods and How to Work Around It
This article explains the limits of annotation inheritance in Java, demonstrates why subclass methods cannot automatically inherit parent annotations, and shows how to use @Inherited, Spring's AnnotatedElementUtils, and find/get semantics to retrieve inherited annotations effectively.
Annotation inheritance in Java
Annotations supply metadata that frameworks such as Spring read from classes and methods (e.g., @Service, @Controller) to enable declarative configuration.
When a subclass overrides a method, annotations declared on the superclass method are not inherited. Java only supports inheritance of class‑level annotations when the annotation type is itself annotated with @Inherited. Method‑level annotations are never inherited, and class‑level annotations are ignored when querying a method on a subclass.
Custom annotation example
Define a custom annotation:
import java.lang.annotation.*;
@Inherited
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
Class<?> value();
}```java @MyAnnotation(value = String.class) public class Parent { @MyAnnotation(value = Integer.class) public void foo() {} } public class Child extends Parent { @Override public void foo() {} } ```
Using reflection:
MyAnnotation classAnno = Parent.class.getAnnotation(MyAnnotation.class); // present
MyAnnotation methodAnno = Parent.class.getMethod("foo").getAnnotation(MyAnnotation.class); // present
MyAnnotation childClassAnno = Child.class.getAnnotation(MyAnnotation.class); // null
MyAnnotation childMethodAnno = Child.class.getMethod("foo").getAnnotation(MyAnnotation.class); // nullThe subclass does not inherit either the class or method annotation.
Effect of @Inherited
Annotating an annotation type with @Inherited allows subclasses to inherit the annotation on the class level only. It has no effect on method annotations.
Spring utilities for merged annotations
Spring’s AnnotatedElementUtils can search the full type hierarchy (including interfaces and bridge methods) and merge annotations. It provides two search strategies:
Find semantics – traverses superclasses, interfaces, and bridge methods to locate annotations.
Get semantics – returns only annotations directly present or inherited via @Inherited on classes.
Key methods: findAllMergedAnnotations(element, annotationType) – uses SearchStrategy.TYPE_HIERARCHY to locate annotations anywhere in the hierarchy. getAllMergedAnnotations(element, annotationType) – uses SearchStrategy.INHERITED_ANNOTATIONS to return only locally declared or class‑inherited annotations.
Spring’s core stereotypes
Annotations such as @Service and @Controller are not designed to be inherited. Even if a subclass overrides a method, Spring does not treat the annotation as present, avoiding ambiguous bean definitions because these beans are singleton by default.
References
Spring Framework issue discussion: https://github.com/spring-projects/spring-framework/issues/8859
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
JavaEdge
First‑line development experience at multiple leading tech firms; now a software architect at a Shanghai state‑owned enterprise and founder of Programming Yanxuan. Nearly 300k followers online; expertise in distributed system design, AIGC application development, and quantitative finance investing.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
