Vaadin Spring Boot: Interference with @Autowired !?

Probably a silly spring-boot-newbie oversight, gurus kindly have a peek pretty-please…

I am using VaadinSpringBoot and run into the following problem: my model and data classes in package org.owlcms.model don’t get autowired by spring boot. To keep things simple, an autowire of a javax.sql.DataSource doesn’t work for these classes (in fact, it doesn’t seem that any autowiring is taking place.) BUT – setting the Spring logs to debug shows that the proper DataSource singleton is created from application.properties settings, and autowiring DOES take place on my top-level application.

I’ve been able to get ahead with the following crude hack (pointers to the actual full source follow below). This shows that the data source is in fact correctly created by the spring initialization. Package org.owlcms.ui gets scanned and autowired – the web application context is autowired correctly.

[code]
@SpringBootApplication
@ServletComponentScan
public class OwlcmsApplication extends SpringBootServletInitializer implements CommandLineRunner {

@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
    return application.sources(OwlcmsApplication.class);
}

public static void main(String args) {
    SpringApplication.run(OwlcmsApplication.class, args);
}

/**
 * Cannot get autowiring to work directly in the owlcms.model package,
 * the following code is a workaround.
 * 
 * @see org.springframework.boot.CommandLineRunner#run(java.lang.String)
 */
@Autowired
DataSource dataSource;

@Override
public void run(String... args) throws Exception {
    DataSourceSingleton.setDataSource(dataSource);
}

}
[/code]The target class in package org.owlcms.model is shown below. It does not get autowired in spite of things looking correct in the debug-level logs. The same DataSource autowiring that works in the application class does not work here. I have tried all the tricks that came to mind (declaring @Repository, adding basePackages to the declarations in the application, etc.).

@SpringComponent
public class InjectedDatabase extends com.dieselpoint.norm.Database {
    
    /**
     * This is broken, injection does not take place
     */
    @Autowired
    DataSource dataSource;


    @Override
    protected DataSource getDataSource() throws SQLException {
        if (dataSource == null) {
            throw new RuntimeException("autowiring failed to inject data source");
        }
        return dataSource;
    }
    
}

You can find the source code for these files (and obviously, pom.xml, application.propertes and suchlike) starting from this link and navigating nearby

https://sourceforge.net/p/owlcms3/code/ci/develop/tree/src/main/java/org/owlcms/OwlcmsApplication.java

The issue was that you cannot simply do a “new InjectedDatabase()”. A constructor does not create a Spring bean. In order to create a Spring bean, you would need to be in a Spring @Configuration, and have a method with @Bean and @Scope(“prototype”) annotations.

An alternate, correct, solution is as follows – Spring creates one instance of the factory because of @Configuration, and instead of calling “new” directly, the code calls a the newDatabase() method to inject the values in the constructor. The components that need the factory must be marked as @SpringComponent, and have to do a @Autowired DatabaseFactory databaseFactory to get a factory. They can then do a databaseFactory.newDatabase()

@Configuration
public class DatabaseFactory {
    
    @Autowired
    DataSource datasource;
    
    /**
     * Convenience method to get the datasource
     * 
     * @return the datasource
     */
    public DataSource getDatasource() {
        return datasource;
    }

    /**
     * Create a database wrapper with the correct datasource.
     * The object is not Spring-managed (i.e. no    @Bean @Scope("prototype") annotations) because
     * it does not need autowiring -- the datasource is provided through the constructor.
     * 
     * @return a database configured to use the Spring-injected datasource
     */

    public Database newDatabase() {
        return new Database(datasource);
    }
    
}

Which commit sha would be the correct one with non-working autowiring? I could check the source

Thanks Johannes. I found the issue. I had misunderstood one fundamental aspect of autowiring, the fact that if you want a bean to be Spring-managed, it cannot be created with a simple “new”. Either you use Spring to create a singleton (which can have static fields available to instances created later using new, or you use prototype scope in an @Configuration factory to create Spring-managed instances.