radoh
radoh

Reputation: 4815

Custom type conversion of property values

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

Answers (1)

Shawn Clark
Shawn Clark

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

Related Questions