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:
Chris Beams
2012-10-26 19:23:47 +02:00
parent 01272fb0e6
commit 06e34f05a6
5 changed files with 83 additions and 6 deletions

View File

@@ -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 { }