From f9da113943b592e4deaeb66c6ea885aa8a34a631 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Thu, 22 Feb 2018 22:01:37 -0800 Subject: [PATCH] Exclude FileEditor from binding conversion Exclude `FileEditor` from the `BindConverter` since it uses slightly unusual logic to create the file. Specifically, given a value of "." the editor will locate a `ClassPathResource` then return `getFile()` from that resource. For back-compatibility, binding should use the simpler conversion service logic. Fixes gh-12163 --- .../properties/bind/BindConverter.java | 12 ++++++++++ .../ConfigurationPropertiesTests.java | 24 +++++++++++++++++++ .../properties/bind/BindConverterTests.java | 13 ++++++++++ 3 files changed, 49 insertions(+) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/BindConverter.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/BindConverter.java index c25b54f063..75512a09cd 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/BindConverter.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/BindConverter.java @@ -20,6 +20,7 @@ import java.beans.PropertyEditor; import java.lang.annotation.Annotation; import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.function.Consumer; @@ -27,6 +28,7 @@ import java.util.function.Consumer; import org.springframework.beans.BeanUtils; import org.springframework.beans.PropertyEditorRegistry; import org.springframework.beans.SimpleTypeConverter; +import org.springframework.beans.propertyeditors.FileEditor; import org.springframework.boot.convert.ApplicationConversionService; import org.springframework.core.ResolvableType; import org.springframework.core.convert.ConversionService; @@ -43,6 +45,13 @@ import org.springframework.util.Assert; */ class BindConverter { + private static final Set> EXCLUDED_EDITORS; + static { + Set> excluded = new HashSet<>(); + excluded.add(FileEditor.class); // gh-12163 + EXCLUDED_EDITORS = Collections.unmodifiableSet(excluded); + } + private final ConversionService typeConverterConversionService; private final ConversionService conversionService; @@ -163,6 +172,9 @@ class BindConverter { if (editor == null && String.class != type) { editor = BeanUtils.findEditorByConvention(type); } + if (editor == null || EXCLUDED_EDITORS.contains(editor.getClass())) { + return null; + } return editor; } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesTests.java index 8106a2e7a0..e48a3e447b 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesTests.java @@ -17,6 +17,7 @@ package org.springframework.boot.context.properties; import java.beans.PropertyEditorSupport; +import java.io.File; import java.time.Duration; import java.util.ArrayList; import java.util.Collections; @@ -737,6 +738,13 @@ public class ConfigurationPropertiesTests { assertThat(bean.getList()).containsExactly(RuntimeException.class); } + @Test + public void loadWhenBindingCurrentDirectoryToFileShouldBind() { + load(FileProperties.class, "test.file=."); + FileProperties bean = this.context.getBean(FileProperties.class); + assertThat(bean.getFile()).isEqualTo(new File(".")); + } + private AnnotationConfigApplicationContext load(Class configuration, String... inlinedProperties) { return load(new Class[] { configuration }, inlinedProperties); @@ -1624,6 +1632,22 @@ public class ConfigurationPropertiesTests { } + @EnableConfigurationProperties + @ConfigurationProperties(prefix = "test") + static class FileProperties { + + private File file; + + public File getFile() { + return this.file; + } + + public void setFile(File file) { + this.file = file; + } + + } + static class CustomPropertiesValidator implements Validator { @Override diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BindConverterTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BindConverterTests.java index 2ec6380110..00e004affc 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BindConverterTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BindConverterTests.java @@ -17,6 +17,7 @@ package org.springframework.boot.context.properties.bind; import java.beans.PropertyEditorSupport; +import java.io.File; import java.util.List; import java.util.function.Consumer; @@ -195,6 +196,18 @@ public class BindConverterTests { bindConverter.convert("test", ResolvableType.forClass(SampleType.class)); } + @Test + public void convertWhenConvertingToFileShouldExcludeFileEditor() { + // For back compatibility we want true file conversion and not an accidental + // classpath resource reference. See gh-12163 + BindConverter bindConverter = new BindConverter(new GenericConversionService(), + null); + assertThat(bindConverter.canConvert(".", ResolvableType.forClass(File.class))) + .isFalse(); + this.thrown.expect(ConverterNotFoundException.class); + bindConverter.convert(".", ResolvableType.forClass(File.class)); + } + private BindConverter getPropertyEditorOnlyBindConverter( Consumer propertyEditorInitializer) { return new BindConverter(new ThrowingConversionService(),