Derek Mahar Derek Mahar - 1 year ago 55
Java Question

How can an application inform the Spring application context where to find a class whose constructor is annotated with @Inject?

How can I fix the following example in order to inform the Spring application context where to find a class

Application
whose constructor is annotated with
@Inject
, but without introducing a bean method to
ApplicationConfiguration
annotated with
@Bean
that returns an instance of class
Application
?

public class Application {
private final A a;

@Inject
public Application(A a) {
this.a = a;
}

public A getA() {
return a;
}
}

@Configuration
public class ApplicationConfiguration {
@Bean
public A getA() {
return new A();
}
}

public class A {
}

public class Start {
public static void main(String[] arguments) {
final ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfiguration.class);
final Application application = context.getBean(Application.class);
application.getA();
}
}


You can review the source code in the AtInject project on GitHub.

When I run class
Start
, Spring complains that it cannot find class
Application
:

May 27, 2016 4:49:55 PM org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@7eda2dbb: startup date [Fri May 27 16:49:55 EDT 2016]; root of context hierarchy
May 27, 2016 4:49:55 PM org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor <init>
INFO: JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.opessoftware.atinject.application.Application] is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:371)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:331)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:975)
at com.opessoftware.atinject.start.Start.main(Start.java:11)

Answer Source

Following M. Deinum's advice, I annotated class Application with stereotype @Component to tell Spring to treat Application as a bean and annotated class ApplicationConfiguration with @ComponentScan in order to direct Spring where to find component Application:

@Component
public class Application {
    private final A a;

    @Inject
    public Application(A a) {
        this.a = a;
    }

    public A getA() {
        return a;
    }
}

@Configuration
@ComponentScan({"me.derekmahar.atinject.application", "me.derekmahar.atinject.model"})
public class ApplicationConfiguration {
    @Bean
    public A getA() {
        return new A("A1");
    }
}

Note that I also modified class A so that it accepts a name:

public class A {
    private final String name;

    public A(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

Class Start now correctly prints "Name of a1 is "A1".":

May 30, 2016 11:14:49 AM org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@7eda2dbb: startup date [Mon May 30 11:14:49 EDT 2016]; root of context hierarchy
May 30, 2016 11:14:49 AM org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor <init>
INFO: JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
Name of a1 is "A1".

You can find the source code to the solution in the AtInject project on GitHub.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download