Fix configprops endpoint's handling of config tree values
Fixes gh-27327
This commit is contained in:
parent
2d3006171d
commit
7a23a12ce0
|
@ -298,7 +298,7 @@ public class ConfigurationPropertiesReportEndpoint implements ApplicationContext
|
|||
|
||||
private Map<String, Object> getInput(String property, ConfigurationProperty candidate) {
|
||||
Map<String, Object> input = new LinkedHashMap<>();
|
||||
Object value = candidate.getValue();
|
||||
Object value = stringifyIfNecessary(candidate.getValue());
|
||||
Origin origin = Origin.from(candidate);
|
||||
List<Origin> originParents = Origin.parentsFrom(candidate);
|
||||
input.put("value", this.sanitizer.sanitize(property, value));
|
||||
|
@ -309,6 +309,16 @@ public class ConfigurationPropertiesReportEndpoint implements ApplicationContext
|
|||
return input;
|
||||
}
|
||||
|
||||
private Object stringifyIfNecessary(Object value) {
|
||||
if (value == null || value.getClass().isPrimitive()) {
|
||||
return value;
|
||||
}
|
||||
if (CharSequence.class.isAssignableFrom(value.getClass())) {
|
||||
return value.toString();
|
||||
}
|
||||
return "Complex property value " + value.getClass().getName();
|
||||
}
|
||||
|
||||
private String getQualifiedKey(String prefix, String key) {
|
||||
return (prefix.isEmpty() ? prefix : prefix + ".") + key;
|
||||
}
|
||||
|
|
|
@ -16,8 +16,12 @@
|
|||
|
||||
package org.springframework.boot.actuate.context.properties;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.InetAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -28,11 +32,16 @@ import org.junit.jupiter.api.Test;
|
|||
import org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpoint.ApplicationConfigurationProperties;
|
||||
import org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpoint.ConfigurationPropertiesBeanDescriptor;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.ConfigurationPropertiesBinding;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
import org.springframework.core.io.InputStreamSource;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.entry;
|
||||
|
@ -238,6 +247,43 @@ class ConfigurationPropertiesReportEndpointSerializationTests {
|
|||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void endpointResponseUsesToStringOfCharSequenceAsPropertyValue() throws IOException {
|
||||
ApplicationContextRunner contextRunner = new ApplicationContextRunner().withInitializer((context) -> {
|
||||
ConfigurableEnvironment environment = context.getEnvironment();
|
||||
environment.getPropertySources().addFirst(new MapPropertySource("test",
|
||||
Collections.singletonMap("foo.name", new CharSequenceProperty("Spring Boot"))));
|
||||
}).withUserConfiguration(FooConfig.class);
|
||||
contextRunner.run((context) -> {
|
||||
ConfigurationPropertiesReportEndpoint endpoint = context
|
||||
.getBean(ConfigurationPropertiesReportEndpoint.class);
|
||||
ApplicationConfigurationProperties applicationProperties = endpoint.configurationProperties();
|
||||
ConfigurationPropertiesBeanDescriptor descriptor = applicationProperties.getContexts().get(context.getId())
|
||||
.getBeans().get("foo");
|
||||
assertThat((Map<String, Object>) descriptor.getInputs().get("name")).containsEntry("value", "Spring Boot");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void endpointResponseUsesPlaceholderForComplexValueAsPropertyValue() throws IOException {
|
||||
ApplicationContextRunner contextRunner = new ApplicationContextRunner().withInitializer((context) -> {
|
||||
ConfigurableEnvironment environment = context.getEnvironment();
|
||||
environment.getPropertySources().addFirst(new MapPropertySource("test",
|
||||
Collections.singletonMap("foo.name", new ComplexProperty("Spring Boot"))));
|
||||
}).withUserConfiguration(ComplexPropertyToStringConverter.class, FooConfig.class);
|
||||
contextRunner.run((context) -> {
|
||||
ConfigurationPropertiesReportEndpoint endpoint = context
|
||||
.getBean(ConfigurationPropertiesReportEndpoint.class);
|
||||
ApplicationConfigurationProperties applicationProperties = endpoint.configurationProperties();
|
||||
ConfigurationPropertiesBeanDescriptor descriptor = applicationProperties.getContexts().get(context.getId())
|
||||
.getBeans().get("foo");
|
||||
assertThat((Map<String, Object>) descriptor.getInputs().get("name")).containsEntry("value",
|
||||
"Complex property value " + ComplexProperty.class.getName());
|
||||
});
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableConfigurationProperties
|
||||
static class Base {
|
||||
|
@ -518,4 +564,59 @@ class ConfigurationPropertiesReportEndpointSerializationTests {
|
|||
|
||||
}
|
||||
|
||||
static class CharSequenceProperty implements CharSequence, InputStreamSource {
|
||||
|
||||
private final String value;
|
||||
|
||||
CharSequenceProperty(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int length() {
|
||||
return this.value.length();
|
||||
}
|
||||
|
||||
@Override
|
||||
public char charAt(int index) {
|
||||
return this.value.charAt(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence subSequence(int start, int end) {
|
||||
return this.value.subSequence(start, end);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream() throws IOException {
|
||||
return new ByteArrayInputStream(this.value.getBytes());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class ComplexProperty {
|
||||
|
||||
private final String value;
|
||||
|
||||
ComplexProperty(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ConfigurationPropertiesBinding
|
||||
static class ComplexPropertyToStringConverter implements Converter<ComplexProperty, String> {
|
||||
|
||||
@Override
|
||||
public String convert(ComplexProperty source) {
|
||||
return source.value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue