Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@ConfigurationProperties bug when a property is a list of classes #6240

Closed
mkopylec opened this issue Jun 28, 2016 · 4 comments
Closed

@ConfigurationProperties bug when a property is a list of classes #6240

mkopylec opened this issue Jun 28, 2016 · 4 comments

Comments

@mkopylec
Copy link
Contributor

mkopylec commented Jun 28, 2016

I'm using 1.3.5.RELEASE version.
I have a configuration class:

@ConfigurationProperties("sample")
public class SampleProperties {

    public static final List<Class<? extends Throwable>> DEFAULT_CLASSES = asList(Exception.class, RuntimeException.class);

    private List<Class<? extends Throwable>> classes = new ArrayList<>(DEFAULT_CLASSES);

    public List<Class<? extends Throwable>> getClasses() {
        return classes;
    }

    public void setClasses(List<Class<? extends Throwable>> classes) {
        this.classes = classes;
    }
}

and application.yml file:

sample.classes: java.io.IOException, java.lang.IllegalArgumentException

Now I expect classes to be [java.io.IOException, java.lang.IllegalArgumentException] but they are [java.lang.Exception, java.lang.RuntimeException]

See the demo project for more details.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jun 28, 2016
@mkopylec mkopylec changed the title @ConfigurationProperties bug when property is a list of classes @ConfigurationProperties bug when a property is a list of classes Jun 28, 2016
@wilkinsona
Copy link
Member

Thanks for the sample. I see what's going on now.

The problem is that the underlying support in Spring Framework for property conversion can't convert a comma-separate String into a List of classes. Instead, it tries to load a class named java.io.IOException, java.lang.IllegalArgumentException. This happens silently as there's no Validator. If you add Hibernate Validator to the classpath, a failure is reported and the app fails to start:

Caused by: org.springframework.validation.BindException: org.springframework.boot.bind.RelaxedDataBinder$RelaxedBeanPropertyBindingResult: 1 errors
Field error in object 'sample' on field 'classes': rejected value [java.io.IOException, java.lang.IllegalArgumentException]; codes [typeMismatch.sample.classes,typeMismatch.classes,typeMismatch.java.util.List,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [sample.classes,classes]; arguments []; default message [classes]]; default message [Failed to convert property value of type [java.lang.String] to required type [java.util.List] for property 'classes'; nested exception is java.lang.IllegalArgumentException: Cannot find class [java.io.IOException, java.lang.IllegalArgumentException]]
    at org.springframework.boot.bind.PropertiesConfigurationFactory.validate(PropertiesConfigurationFactory.java:362) ~[spring-boot-1.3.5.RELEASE.jar:1.3.5.RELEASE]
    at org.springframework.boot.bind.PropertiesConfigurationFactory.doBindPropertiesToTarget(PropertiesConfigurationFactory.java:271) ~[spring-boot-1.3.5.RELEASE.jar:1.3.5.RELEASE]
    at org.springframework.boot.bind.PropertiesConfigurationFactory.bindPropertiesToTarget(PropertiesConfigurationFactory.java:241) ~[spring-boot-1.3.5.RELEASE.jar:1.3.5.RELEASE]
    at org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.postProcessBeforeInitialization(ConfigurationPropertiesBindingPostProcessor.java:334) ~[spring-boot-1.3.5.RELEASE.jar:1.3.5.RELEASE]
    ... 31 common frames omitted

If you'd like Spring Framework to be able to support this comma-separated String to List<Class> conversion then you could raise a JIRA ticket requesting it.

In the meantime, you could add your own converter:

    @ConfigurationPropertiesBinding
    @Bean
    public Converter<String, List<Class<? extends Throwable>>> customConverter() {
        return new Converter<String, List<Class<? extends Throwable>>>() {

            @SuppressWarnings("unchecked")
            @Override
            public List<Class<? extends Throwable>> convert(String source) {
                try {
                    List<Class<? extends Throwable>> classes = new ArrayList<>();
                    for (String className: StringUtils.commaDelimitedListToStringArray(source)) {
                        classes.add((Class<? extends Throwable>)ClassUtils.forName(className.trim(),
                                getClass().getClassLoader()));
                    }
                    return classes;
                } catch (ClassNotFoundException ex) {
                    ex.printStackTrace();
                    throw new IllegalStateException(ex);
                }
            }

        };

    }

@wilkinsona wilkinsona removed the status: waiting-for-triage An issue we've not yet triaged label Jun 28, 2016
@mkopylec
Copy link
Contributor Author

Thanks again!

@yuhuanxi
Copy link

thanks

@philwebb
Copy link
Member

This looks very similar to #12166 so you might want to consider upgrading to Spring Boot 2.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants