Reputation: 511
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?
Upvotes: 1
Views: 2082
Reputation: 77206
Unmitigated provided a one-line answer, but the traditional mechanism (or one that simply avoids any Spring coupling at all with the implementation class) is to use an @Bean
method in an @Configuration
class, where you pass the properties object as a parameter and "unwind" it in the service's constructor:
@Bean
MyService(MyProperties props) {
return new MyServiceImpl(props.getFoo(), props.getBar());
}
Note that your jdbc
bits seem to duplicate the out-of-the-box auto-configuration for JDBC; prefer the defaults when practical.
Upvotes: 0
Reputation: 89404
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;
}
}
Upvotes: 3
Reputation: 120978
If you really want to use @Value
, it must have the form: @Value("app.name") String name
; but you do not want to use it anyway. Spring favors @ConfigurationProperties
for a long time now, and @Value
does not work with relaxed binding either.
Upvotes: 0