Reputation: 4815
I have a myapp.properties
file with key-value pairs defined as:
prefix.int-field=123
prefix.string-field=asdf
prefix.custom-type-field=my.package.CustomType
I am trying to inject these properties by using a @Value
annotation in a following class:
@PropertySource(value = "classpath:myapp.properties")
@Component
class MySettings {
@Value("${prefix.int-field}")
private int intField;
@Value("${prefix.string-field}")
private String stringField;
@Value("${prefix.custom-type-field}") // <-- this is the problem
private CustomInterface customField;
}
class CustomType implements CustomInterface {...}
interface CustomInterface {...}
Now, intField
and stringField
get initialized with the desired values as expected, but customField
throws an exception:
Caused by: java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [my.package.CustomInterface]: no matching editors or conversion strategy found
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:303) ~[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:125) ~[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
at org.springframework.beans.TypeConverterSupport.doConvert(TypeConverterSupport.java:61) ~[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
How can I convert the text property values to my custom type?
I tried to consult the documentation, but I fail to see the correct way of doing it. I am using Spring Boot 1.3.6.
Upvotes: 2
Views: 6246
Reputation: 3440
To resolve your immediate issue you want to look at the @PostConstruct
option on the bean. That will allow you to act on things before the bean is made available to the context.
@PropertySource(value = "classpath:myapp.properties")
@Component
class MySettings {
@Value("${prefix.int-field}")
private int intField;
@Value("${prefix.string-field}")
private String stringField;
@Value("${prefix.custom-type-field}")
private String customFieldType;
private CustomInterface customField;
@PostConstruct
public void init() {
customField = (CustomInterface) Class.forName(customFieldType).newInstance(); // short form... will need checks that it finds the class and can create a new instance
}
}
class CustomType implements CustomInterface {...}
interface CustomInterface {...}
I am curious if you might want to use the @Configuration
annotation on a class and create an instance of the CustomInterface
that is made available as a bean on the Spring ApplicationContext. To do that you would instead do something like this:
@Component
@ConfigurationProperties(prefix = "prefix")
class MySettings {
private int intField;
private String stringField;
private String customTypeField;
// getters and setters
}
That would then be used in an @Configuration
class:
@Configuration
class MyConfiguration {
@Bean
public CustomInterface customInterface(MySettings mySettings) {
return (CustomInterface) Class.forName(mySettings.getCustomTypeField()).newInstance();
}
}
At this point you would now have an instantiated bean for CustomInterface
that you can have Spring autowire into other objects.
Upvotes: 1