Charbel
Charbel

Reputation: 14687

Spring @Autowire is behaving in a weird way returning null for initialized bean

I have a legacy spring application, with a mix of xml and java config. (not my choice sorry). The spring context is initialized from the xml config, which has a component scan instruction to scan the java configs.

There are many java config classes, below are code snippets from 2 of them where I see a problem. My @Bean DateProvider dateProvider() in ReplayConfig is initialized first, and I can see this by putting a breakpoint in the constructor. And then in AnotherConfig I autowire @Autowired private DateProvider dateProvider; After having used @Import(ReplayConfig.class).

All good so far, except it turns out the instance of my portfolioService has been passed a null dateProvider. It is frustrating to see experience this, given I can clearly see that dateProvider has been instantiated earlier.

I can actually get it to work if I add to PortfolioServiceImpl

@Autowired setDateProvider(DateProvider dateProvider) 

Which I thought would remove all doubt about possibility of confusing packages or different classes with the same name or silly things like that.

The only thing I can think of is something else is wrong. If someone can suggest any ideas it would be great.

Unfortunately I can't get away from the xml initialisation for now.

More code below:

@Import (EnvironmentConfig.class)
@Config
ReplayConfig{
   @Bean
    DateProvider dateProvider() {
        SystemDateProvider systemDateProvider = new SystemDateProvider (bean());
        return systemDateProvider;
    }
}

Then we import that and try to auto wire dateProvider

 @Import(ReplayConfig.class)
    @Configuration
    public class AnotherConfig {
        @Autowired
        private DateProvider dateProvider;

        @Bean
        PortfolioService portfolioService() {
            PortfolioService  portfolioService = new PortfolioServiceImpl(dateProvider, bean(),otherBean());
            return portfolioService 
        }
    }

this is how we trigger component scan:

<!--******************************************  Scan for JavaConfig  ******************************************-->
<context:component-scan base-package="com.app.config, com.app.common.config">
         <context:exclude-filter type="regex" expression="com\.app\.a4\.systest.*"/>
         <context:exclude-filter type="regex" expression="com\.app\.common\.systest.*"/>
</context:component-scan>

And here's how we start the application, and create the context:

public static void main(String[] args) {

        try(ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(getResourcePath())){
            context.setClassLoader(Thread.currentThread().getContextClassLoader());
        }
}

Upvotes: 0

Views: 228

Answers (1)

pamykyta
pamykyta

Reputation: 658

I guess instead of Autowiring dateProvider to your AnotherConfig you can try to adjust bean declaration of portfolioService to the following one:

@Bean
PortfolioService portfolioService(DateProvider dateProvider) {
    PortfolioService  portfolioService = new PortfolioServiceImpl(dateProvider, bean(),otherBean());
    return portfolioService 
}

Upvotes: 1

Related Questions