Search code examples
javaspring-bootpropertiesyamlinversion-of-control

Spring Boot and constructor injection


I'm building a new Springboot application, and I'm a bit confused about constructor injection for properties. I'm reading values from a yaml file. And the yaml looks like this:

app:
  name: myApplication
  jdbc:
      jdbcUrl: "jdbc:postgresql://localhost:5432/MyDb"
      driverClassName: org.postgresql.Driver
      maximumPoolSize: 1
      username: domainmanager
      password: password

This is being read into two objects, once which processes the name and the jdbc data is held into a second object.

@Configuration
@ConfigurationProperties(prefix = "app")
public class AppConfig {
    private String name;
    private DataSourceInfo jdbc;

If I use setter based injection everything seems to work perfectly. But I'd really like to use constructor injection but when I add this constructor:

    public AppConfig(    @Value("name") String name,
                         @Value("jdbc") DataSourceInfo dsInfo) {
        this.name = name;
        this.jdbc = dsInfo;
    }

Gives me this error:

Cannot convert value of type 'java.lang.String' to required type 'com.ecomm.properties.DataSourceInfo': no matching editors or conversion strategy found

The DataSourceInfo class is annotated like this:

@Configuration
@ConfigurationProperties(prefix = "jdbc")
public class DataSourceInfo {
    private String jdbcUrl;
    private String driverClassName;
    private String maximumPoolSize;
    private String username;
    private String password;
    private String type;

What am I missing? How do I convince the inversion of control container that it needs to inject an object and not a try to convert a string to an object? Is that even what's happening?


Solution

  • Use the @ConstructorBinding annotation.

    @ConfigurationProperties(prefix = "app")
    @ConstructorBinding
    public class AppConfig {
        private String name;
        private DataSourceInfo jdbc;
        public AppConfig(String name, DataSourceInfo jdbc) {
            this.name = name;
            this.jdbc = jdbc;
        }
    }