Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't get @Component to be inherited in Spring?

In my project there's a common base class that all client classes extend. This has an @Autowired field that needs to be injected by Hibernate. These are all grouped together in another class that has an @Autowired collection of the base class.

In order to reduce boilerplate for client code I'm trying to get @Component inherited. With @Component not doing this by default (apparently it used to though), I created this workaround annotation

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Component
@Inherited
public @interface InheritedComponent {
}

... and annotated the base class with it. Its not pretty but I hoped it would work. Unfortunately it didn't, which really confuses me as @Inherited should make it work

Is there any other way to get @Component inherited? Or do I just have to say that any class that extends the base class needs this boilerplate?

like image 290
TheLQ Avatar asked Aug 02 '11 12:08

TheLQ


People also ask

Is @component and @bean same?

@Component is a class-level annotation, but @Bean is at the method level, so @Component is only an option when a class's source code is editable. @Bean can always be used, but it's more verbose. @Component is compatible with Spring's auto-detection, but @Bean requires manual class instantiation.

Can we use @component instead of @service in Spring?

We can use @Component across the application to mark the beans as Spring's managed components. Spring will only pick up and register beans with @Component, and doesn't look for @Service and @Repository in general. @Service and @Repository are special cases of @Component.

Is @component a bean in Spring?

No. It is used to explicitly declare a single bean, rather than letting Spring do it automatically. If any class is annotated with @Component it will be automatically detect by using classpath scan. We should use @bean, if you want specific implementation based on dynamic condition.

Can we use @component instead of @controller in Spring?

Spring provides four different types of auto component scan annotations, they are @Component , @Service , @Repository and @Controller . Technically, there is no difference between them, but every auto component scan annotation should be used for a special purpose and within the defined layer.


2 Answers

The problem is that the Component annotation type itself needs to be marked with @Inherited.

Your @InheritedComponent annotation type is correctly inherited by any classes that extend a superclass which is marked with @InheritedComponent - but it does not inherit @Component. This is because you have @Component on the annotation, not the parent type.

An example:

public class InheritedAnnotationTest {

    @InheritedComponent
    public static class BaseComponent {
    }

    public static class SubClass extends BaseComponent {
    }

    public static void main(String[] args) {
        SubClass s = new SubClass();

        for (Annotation a : s.getClass().getAnnotations()) {
            System.out.printf("%s has annotation %s\n", s.getClass(), a);
        }
    }
}

Output:

class brown.annotations.InheritedAnnotationTest$SubClass has annotation @brown.annotations.InheritedComponent()

In other words, when resolving what annotations a class has, the annotations of the annotations are not resolved - they do not apply to the class, only the annotation (if that makes sense).

like image 155
matt b Avatar answered Sep 28 '22 18:09

matt b


I've dealt with this issue by creating my own annotation (heritable) and then customizing classpath scanning:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Component 
@Inherited
public @interface BusinessService {
}

Spring configuration look likes this:

<context:component-scan base-package="io.bar">
        <context:include-filter type="annotation"
            expression="io.bar.core.annotations.BusinessService" />
    </context:component-scan>

from Spring doc 5.10.3 Using filters to customize scanning

like image 33
noleto Avatar answered Sep 28 '22 20:09

noleto