Allow PropertyResolvers to ignore unresolvable ${placeholders}
Prior to this commit, the PropertyResolver API (and therefore the Environment API) allowed callers a choice between #resolvePlaceholders and #resolveRequiredPlaceholders for low-level ${placeholder} resolution. However, when calling the higher level #getProperty variants, users had no control over whether property values returned with unresolvable ${placeholders} would result in an exception or simply be passed through. This commit introduces a #setIgnoreUnresolvableNestedPlaceholders property via ConfigurablePropertyResolver, defaulting to false, the value of which is respected by AbstractPropertyResolver#getProperty method implementations. See the new test in PropertySourcesPropertyResolverTests for usage examples. Issue: SPR-9569, SPR-9473
This commit is contained in:
parent
01272fb0e6
commit
06e34f05a6
|
@ -464,6 +464,10 @@ public abstract class AbstractEnvironment implements ConfigurableEnvironment {
|
|||
return this.propertyResolver.resolveRequiredPlaceholders(text);
|
||||
}
|
||||
|
||||
public void setIgnoreUnresolvableNestedPlaceholders(boolean ignoreUnresolvableNestedPlaceholders) {
|
||||
this.propertyResolver.setIgnoreUnresolvableNestedPlaceholders(ignoreUnresolvableNestedPlaceholders);
|
||||
}
|
||||
|
||||
public void setConversionService(ConfigurableConversionService conversionService) {
|
||||
this.propertyResolver.setConversionService(conversionService);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -45,6 +45,7 @@ public abstract class AbstractPropertyResolver implements ConfigurablePropertyRe
|
|||
|
||||
private PropertyPlaceholderHelper nonStrictHelper;
|
||||
private PropertyPlaceholderHelper strictHelper;
|
||||
private boolean ignoreUnresolvableNestedPlaceholders = false;
|
||||
|
||||
private String placeholderPrefix = PLACEHOLDER_PREFIX;
|
||||
private String placeholderSuffix = PLACEHOLDER_SUFFIX;
|
||||
|
@ -142,6 +143,28 @@ public abstract class AbstractPropertyResolver implements ConfigurablePropertyRe
|
|||
return doResolvePlaceholders(text, strictHelper);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>The default value for this implementation is {@code false}.
|
||||
* @since 3.2
|
||||
*/
|
||||
public void setIgnoreUnresolvableNestedPlaceholders(boolean ignoreUnresolvableNestedPlaceholders) {
|
||||
this.ignoreUnresolvableNestedPlaceholders = ignoreUnresolvableNestedPlaceholders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve placeholders within the given string, deferring to the value of
|
||||
* {@link #setIgnoreUnresolvableNestedPlaceholders(boolean)} to determine whether any
|
||||
* unresolvable placeholders should raise an exception or be ignored.
|
||||
* @since 3.2
|
||||
* @see #setIgnoreUnresolvableNestedPlaceholders(boolean)
|
||||
*/
|
||||
protected String resolveNestedPlaceholders(String value) {
|
||||
return this.ignoreUnresolvableNestedPlaceholders ?
|
||||
this.resolvePlaceholders(value) :
|
||||
this.resolveRequiredPlaceholders(value);
|
||||
}
|
||||
|
||||
private PropertyPlaceholderHelper createPlaceholderHelper(boolean ignoreUnresolvablePlaceholders) {
|
||||
return new PropertyPlaceholderHelper(this.placeholderPrefix, this.placeholderSuffix,
|
||||
this.valueSeparator, ignoreUnresolvablePlaceholders);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -87,4 +87,17 @@ public interface ConfigurablePropertyResolver extends PropertyResolver {
|
|||
* properties are not resolvable.
|
||||
*/
|
||||
void validateRequiredProperties() throws MissingRequiredPropertiesException;
|
||||
|
||||
/**
|
||||
* Set whether to throw an exception when encountering an unresolvable placeholder
|
||||
* nested within the value of a given property. A {@code false} value indicates strict
|
||||
* resolution, i.e. that an exception will be thrown. A {@code true} value indicates
|
||||
* that unresolvable nested placeholders should be passed through in their unresolved
|
||||
* ${...} form.
|
||||
* <p>Implementations of {@link #getProperty(String)} and its variants must inspect
|
||||
* the value set here to determine correct behavior when property values contain
|
||||
* unresolvable placeholders.
|
||||
* @since 3.2
|
||||
*/
|
||||
void setIgnoreUnresolvableNestedPlaceholders(boolean ignoreUnresolvableNestedPlaceholders);
|
||||
}
|
||||
|
|
|
@ -73,7 +73,7 @@ public class PropertySourcesPropertyResolver extends AbstractPropertyResolver {
|
|||
if ((value = propertySource.getProperty(key)) != null) {
|
||||
Class<?> valueType = value.getClass();
|
||||
if (String.class.equals(valueType)) {
|
||||
value = this.resolveRequiredPlaceholders((String) value);
|
||||
value = this.resolveNestedPlaceholders((String) value);
|
||||
}
|
||||
if (debugEnabled) {
|
||||
logger.debug(
|
||||
|
|
|
@ -20,8 +20,6 @@ import java.util.HashMap;
|
|||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hamcrest.CoreMatchers;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -364,7 +362,7 @@ public class PropertySourcesPropertyResolverTests {
|
|||
.withProperty("pL", "${pR}") // cyclic reference left
|
||||
.withProperty("pR", "${pL}") // cyclic reference right
|
||||
);
|
||||
PropertySourcesPropertyResolver pr = new PropertySourcesPropertyResolver(ps);
|
||||
ConfigurablePropertyResolver pr = new PropertySourcesPropertyResolver(ps);
|
||||
assertThat(pr.getProperty("p1"), equalTo("v1"));
|
||||
assertThat(pr.getProperty("p2"), equalTo("v2"));
|
||||
assertThat(pr.getProperty("p3"), equalTo("v1:v2"));
|
||||
|
@ -383,6 +381,45 @@ public class PropertySourcesPropertyResolverTests {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ignoreUnresolvableNestedPlaceholdersIsConfigurable() {
|
||||
MutablePropertySources ps = new MutablePropertySources();
|
||||
ps.addFirst(new MockPropertySource()
|
||||
.withProperty("p1", "v1")
|
||||
.withProperty("p2", "v2")
|
||||
.withProperty("p3", "${p1}:${p2}:${bogus:def}") // unresolvable w/ default
|
||||
.withProperty("p4", "${p1}:${p2}:${bogus}") // unresolvable placeholder
|
||||
);
|
||||
ConfigurablePropertyResolver pr = new PropertySourcesPropertyResolver(ps);
|
||||
assertThat(pr.getProperty("p1"), equalTo("v1"));
|
||||
assertThat(pr.getProperty("p2"), equalTo("v2"));
|
||||
assertThat(pr.getProperty("p3"), equalTo("v1:v2:def"));
|
||||
|
||||
// placeholders nested within the value of "p4" are unresolvable and cause an
|
||||
// exception by default
|
||||
try {
|
||||
pr.getProperty("p4");
|
||||
} catch (IllegalArgumentException ex) {
|
||||
assertThat(ex.getMessage(), containsString(
|
||||
"Could not resolve placeholder 'bogus' in string value [${p1}:${p2}:${bogus}]"));
|
||||
}
|
||||
|
||||
// relax the treatment of unresolvable nested placeholders
|
||||
pr.setIgnoreUnresolvableNestedPlaceholders(true);
|
||||
// and observe they now pass through unresolved
|
||||
assertThat(pr.getProperty("p4"), equalTo("v1:v2:${bogus}"));
|
||||
|
||||
// resolve[Nested]Placeholders methods behave as usual regardless the value of
|
||||
// ignoreUnresolvableNestedPlaceholders
|
||||
assertThat(pr.resolvePlaceholders("${p1}:${p2}:${bogus}"), equalTo("v1:v2:${bogus}"));
|
||||
try {
|
||||
pr.resolveRequiredPlaceholders("${p1}:${p2}:${bogus}");
|
||||
} catch (IllegalArgumentException ex) {
|
||||
assertThat(ex.getMessage(), containsString(
|
||||
"Could not resolve placeholder 'bogus' in string value [${p1}:${p2}:${bogus}]"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static interface SomeType { }
|
||||
static class SpecificType implements SomeType { }
|
||||
|
|
Loading…
Reference in New Issue