List valid values in failure analysis for enum binding failure
Closes gh-11771
This commit is contained in:
parent
cedb6b2f17
commit
11064b5d78
|
|
@ -16,12 +16,19 @@
|
|||
|
||||
package org.springframework.boot.diagnostics.analyzer;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.TreeSet;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.boot.context.properties.bind.BindException;
|
||||
import org.springframework.boot.context.properties.bind.UnboundConfigurationPropertiesException;
|
||||
import org.springframework.boot.context.properties.bind.validation.BindValidationException;
|
||||
import org.springframework.boot.context.properties.source.ConfigurationProperty;
|
||||
import org.springframework.boot.diagnostics.AbstractFailureAnalyzer;
|
||||
import org.springframework.boot.diagnostics.FailureAnalysis;
|
||||
import org.springframework.core.convert.ConversionFailedException;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
|
|
@ -46,7 +53,7 @@ class BindFailureAnalyzer extends AbstractFailureAnalyzer<BindException> {
|
|||
|
||||
private FailureAnalysis analyzeGenericBindException(BindException cause) {
|
||||
StringBuilder description = new StringBuilder(
|
||||
String.format("Binding to target %s failed:%n", cause.getTarget()));
|
||||
String.format("%s:%n", cause.getMessage()));
|
||||
ConfigurationProperty property = cause.getProperty();
|
||||
buildDescription(description, property);
|
||||
description.append(String.format("%n Reason: %s", getMessage(cause)));
|
||||
|
|
@ -71,8 +78,29 @@ class BindFailureAnalyzer extends AbstractFailureAnalyzer<BindException> {
|
|||
}
|
||||
|
||||
private FailureAnalysis getFailureAnalysis(Object description, BindException cause) {
|
||||
return new FailureAnalysis(description.toString(),
|
||||
"Update your application's configuration", cause);
|
||||
StringBuilder message = new StringBuilder(
|
||||
"Update your application's configuration");
|
||||
Collection<String> validValues = findValidValues(cause);
|
||||
if (!validValues.isEmpty()) {
|
||||
message.append(String.format(". The following values are valid:%n"));
|
||||
validValues
|
||||
.forEach((value) -> message.append(String.format("%n %s", value)));
|
||||
}
|
||||
return new FailureAnalysis(description.toString(), message.toString(), cause);
|
||||
}
|
||||
|
||||
private Collection<String> findValidValues(BindException ex) {
|
||||
ConversionFailedException conversionFailure = findCause(ex,
|
||||
ConversionFailedException.class);
|
||||
if (conversionFailure != null) {
|
||||
Object[] enumConstants = conversionFailure.getTargetType().getType()
|
||||
.getEnumConstants();
|
||||
if (enumConstants != null) {
|
||||
return Stream.of(enumConstants).map(Object::toString)
|
||||
.collect(Collectors.toCollection(TreeSet::new));
|
||||
}
|
||||
}
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ package org.springframework.boot.diagnostics.analyzer;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.validation.constraints.Min;
|
||||
|
||||
|
|
@ -67,6 +68,15 @@ public class BindFailureAnalyzerTests {
|
|||
"Could not resolve placeholder 'BAR' in value \"${BAR}\""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bindExceptionForUnknownValueInEnumListsValidValuesInAction() {
|
||||
FailureAnalysis analysis = performAnalysis(EnumFailureConfiguration.class,
|
||||
"test.foo.fruit=apple,strawberry");
|
||||
for (Fruit fruit : Fruit.values()) {
|
||||
assertThat(analysis.getAction()).contains(fruit.name());
|
||||
}
|
||||
}
|
||||
|
||||
private static String failure(String property, String value, String origin,
|
||||
String reason) {
|
||||
return String.format(
|
||||
|
|
@ -124,6 +134,11 @@ public class BindFailureAnalyzerTests {
|
|||
|
||||
}
|
||||
|
||||
@EnableConfigurationProperties(EnumFailureProperties.class)
|
||||
static class EnumFailureConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@ConfigurationProperties("test.foo")
|
||||
@Validated
|
||||
static class FieldValidationFailureProperties {
|
||||
|
|
@ -170,4 +185,25 @@ public class BindFailureAnalyzerTests {
|
|||
|
||||
}
|
||||
|
||||
@ConfigurationProperties("test.foo")
|
||||
static class EnumFailureProperties {
|
||||
|
||||
private Set<Fruit> fruit;
|
||||
|
||||
public Set<Fruit> getFruit() {
|
||||
return this.fruit;
|
||||
}
|
||||
|
||||
public void setFruit(Set<Fruit> fruit) {
|
||||
this.fruit = fruit;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
enum Fruit {
|
||||
|
||||
APPLE, BANANA, ORANGE;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue