提交 0f43d6c5 编写于 作者: J Juergen Hoeller

PropertyPlaceholderConfigurer supports "${myKey:myDefaultValue}" defaulting syntax

上级 8eca898d
...@@ -99,6 +99,9 @@ public class PropertyPlaceholderConfigurer extends PropertyResourceConfigurer ...@@ -99,6 +99,9 @@ public class PropertyPlaceholderConfigurer extends PropertyResourceConfigurer
/** Default placeholder suffix: "}" */ /** Default placeholder suffix: "}" */
public static final String DEFAULT_PLACEHOLDER_SUFFIX = "}"; public static final String DEFAULT_PLACEHOLDER_SUFFIX = "}";
/** Default value separator: ":" */
public static final String DEFAULT_VALUE_SEPARATOR = ":";
/** Never check system properties. */ /** Never check system properties. */
public static final int SYSTEM_PROPERTIES_MODE_NEVER = 0; public static final int SYSTEM_PROPERTIES_MODE_NEVER = 0;
...@@ -122,6 +125,8 @@ public class PropertyPlaceholderConfigurer extends PropertyResourceConfigurer ...@@ -122,6 +125,8 @@ public class PropertyPlaceholderConfigurer extends PropertyResourceConfigurer
private String placeholderSuffix = DEFAULT_PLACEHOLDER_SUFFIX; private String placeholderSuffix = DEFAULT_PLACEHOLDER_SUFFIX;
private String valueSeparator = DEFAULT_VALUE_SEPARATOR;
private int systemPropertiesMode = SYSTEM_PROPERTIES_MODE_FALLBACK; private int systemPropertiesMode = SYSTEM_PROPERTIES_MODE_FALLBACK;
private boolean searchSystemEnvironment = true; private boolean searchSystemEnvironment = true;
...@@ -360,7 +365,8 @@ public class PropertyPlaceholderConfigurer extends PropertyResourceConfigurer ...@@ -360,7 +365,8 @@ public class PropertyPlaceholderConfigurer extends PropertyResourceConfigurer
private final PlaceholderResolver resolver; private final PlaceholderResolver resolver;
public PlaceholderResolvingStringValueResolver(Properties props) { public PlaceholderResolvingStringValueResolver(Properties props) {
this.helper = new PropertyPlaceholderHelper(placeholderPrefix, placeholderSuffix, ignoreUnresolvablePlaceholders); this.helper = new PropertyPlaceholderHelper(
placeholderPrefix, placeholderSuffix, valueSeparator, ignoreUnresolvablePlaceholders);
this.resolver = new PropertyPlaceholderConfigurerResolver(props); this.resolver = new PropertyPlaceholderConfigurerResolver(props);
} }
...@@ -370,6 +376,7 @@ public class PropertyPlaceholderConfigurer extends PropertyResourceConfigurer ...@@ -370,6 +376,7 @@ public class PropertyPlaceholderConfigurer extends PropertyResourceConfigurer
} }
} }
private class PropertyPlaceholderConfigurerResolver implements PlaceholderResolver { private class PropertyPlaceholderConfigurerResolver implements PlaceholderResolver {
private final Properties props; private final Properties props;
......
...@@ -662,6 +662,19 @@ public final class PropertyResourceConfigurerTests { ...@@ -662,6 +662,19 @@ public final class PropertyResourceConfigurerTests {
assertEquals("mytest", tb.getTouchy()); assertEquals("mytest", tb.getTouchy());
} }
@Test
public void testPropertyPlaceholderConfigurerWithInlineDefault() {
factory.registerBeanDefinition("tb",
genericBeanDefinition(TestBean.class)
.addPropertyValue("touchy", "${test:mytest}").getBeanDefinition());
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
ppc.postProcessBeanFactory(factory);
TestBean tb = (TestBean) factory.getBean("tb");
assertEquals("mytest", tb.getTouchy());
}
@Test @Test
public void testPropertyPlaceholderConfigurerWithAliases() { public void testPropertyPlaceholderConfigurerWithAliases() {
factory.registerBeanDefinition("tb", factory.registerBeanDefinition("tb",
......
...@@ -16,18 +16,18 @@ ...@@ -16,18 +16,18 @@
package org.springframework.util; package org.springframework.util;
import java.util.HashSet;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.HashSet;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
/** /**
* Utility class for working with Strings that have placeholder values in them. A placeholder takes the form * Utility class for working with Strings that have placeholder values in them. A placeholder takes the form
* <code>${name}</code>. Using <code>PropertyPlaceholderUtils</code> these placeholders can be substituted for * <code>${name}</code>. Using <code>PropertyPlaceholderHelper</code> these placeholders can be substituted for
* user-supplied values. <p> Values for substitution can be supplied using a {@link Properties} instance or using a * user-supplied values. <p> Values for substitution can be supplied using a {@link Properties} instance or
* {@link PlaceholderResolver}. * using a {@link PlaceholderResolver}.
* *
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Rob Harrop * @author Rob Harrop
...@@ -35,46 +35,49 @@ import org.apache.commons.logging.LogFactory; ...@@ -35,46 +35,49 @@ import org.apache.commons.logging.LogFactory;
*/ */
public class PropertyPlaceholderHelper { public class PropertyPlaceholderHelper {
private static final Log LOGGER = LogFactory.getLog(PropertyPlaceholderHelper.class); private static final Log logger = LogFactory.getLog(PropertyPlaceholderHelper.class);
private final String placeholderPrefix; private final String placeholderPrefix;
private final String placeholderSuffix; private final String placeholderSuffix;
private final String valueSeparator;
private final boolean ignoreUnresolvablePlaceholders; private final boolean ignoreUnresolvablePlaceholders;
/** /**
* Creates a new <code>PropertyPlaceholderHelper</code> that uses the supplied prefix and suffix. Unresolvable * Creates a new <code>PropertyPlaceholderHelper</code> that uses the supplied prefix and suffix.
* placeholders are ignored. * Unresolvable placeholders are ignored.
*
* @param placeholderPrefix the prefix that denotes the start of a placeholder. * @param placeholderPrefix the prefix that denotes the start of a placeholder.
* @param placeholderSuffix the suffix that denotes the end of a placeholder. * @param placeholderSuffix the suffix that denotes the end of a placeholder.
*/ */
public PropertyPlaceholderHelper(String placeholderPrefix, String placeholderSuffix) { public PropertyPlaceholderHelper(String placeholderPrefix, String placeholderSuffix) {
this(placeholderPrefix, placeholderSuffix, true); this(placeholderPrefix, placeholderSuffix, null, true);
} }
/** /**
* Creates a new <code>PropertyPlaceholderHelper</code> that uses the supplied prefix and suffix. * Creates a new <code>PropertyPlaceholderHelper</code> that uses the supplied prefix and suffix.
*
* @param placeholderPrefix the prefix that denotes the start of a placeholder. * @param placeholderPrefix the prefix that denotes the start of a placeholder.
* @param placeholderSuffix the suffix that denotes the end of a placeholder. * @param placeholderSuffix the suffix that denotes the end of a placeholder.
* @param ignoreUnresolvablePlaceholders indicates whether unresolvable placeholders should be ignored * @param ignoreUnresolvablePlaceholders indicates whether unresolvable placeholders should be ignored
* (<code>true</code>) or cause an exception (<code>false</code>). * (<code>true</code>) or cause an exception (<code>false</code>).
*/ */
public PropertyPlaceholderHelper(String placeholderPrefix, String placeholderSuffix, public PropertyPlaceholderHelper(String placeholderPrefix, String placeholderSuffix,
boolean ignoreUnresolvablePlaceholders) { String valueSeparator, boolean ignoreUnresolvablePlaceholders) {
Assert.notNull(placeholderPrefix, "Argument 'placeholderPrefix' must not be null.");
Assert.notNull(placeholderSuffix, "Argument 'placeholderSuffix' must not be null."); Assert.notNull(placeholderPrefix, "placeholderPrefix must not be null");
Assert.notNull(placeholderSuffix, "placeholderSuffix must not be null");
this.placeholderPrefix = placeholderPrefix; this.placeholderPrefix = placeholderPrefix;
this.placeholderSuffix = placeholderSuffix; this.placeholderSuffix = placeholderSuffix;
this.valueSeparator = valueSeparator;
this.ignoreUnresolvablePlaceholders = ignoreUnresolvablePlaceholders; this.ignoreUnresolvablePlaceholders = ignoreUnresolvablePlaceholders;
} }
/** /**
* Replaces all placeholders of format <code>${name}</code> with the corresponding property from the supplied {@link * Replaces all placeholders of format <code>${name}</code> with the corresponding property
* Properties}. * from the supplied {@link Properties}.
*
* @param value the value containing the placeholders to be replaced. * @param value the value containing the placeholders to be replaced.
* @param properties the <code>Properties</code> to use for replacement. * @param properties the <code>Properties</code> to use for replacement.
* @return the supplied value with placeholders replaced inline. * @return the supplied value with placeholders replaced inline.
...@@ -82,7 +85,6 @@ public class PropertyPlaceholderHelper { ...@@ -82,7 +85,6 @@ public class PropertyPlaceholderHelper {
public String replacePlaceholders(String value, final Properties properties) { public String replacePlaceholders(String value, final Properties properties) {
Assert.notNull(properties, "Argument 'properties' must not be null."); Assert.notNull(properties, "Argument 'properties' must not be null.");
return replacePlaceholders(value, new PlaceholderResolver() { return replacePlaceholders(value, new PlaceholderResolver() {
public String resolvePlaceholder(String placeholderName) { public String resolvePlaceholder(String placeholderName) {
return properties.getProperty(placeholderName); return properties.getProperty(placeholderName);
} }
...@@ -90,9 +92,8 @@ public class PropertyPlaceholderHelper { ...@@ -90,9 +92,8 @@ public class PropertyPlaceholderHelper {
} }
/** /**
* Replaces all placeholders of format <code>${name}</code> with the value returned from the supplied {@link * Replaces all placeholders of format <code>${name}</code> with the value returned from the supplied
* PlaceholderResolver}. * {@link PlaceholderResolver}.
*
* @param value the value containing the placeholders to be replaced. * @param value the value containing the placeholders to be replaced.
* @param placeholderResolver the <code>PlaceholderResolver</code> to use for replacement. * @param placeholderResolver the <code>PlaceholderResolver</code> to use for replacement.
* @return the supplied value with placeholders replaced inline. * @return the supplied value with placeholders replaced inline.
...@@ -102,8 +103,9 @@ public class PropertyPlaceholderHelper { ...@@ -102,8 +103,9 @@ public class PropertyPlaceholderHelper {
return parseStringValue(value, placeholderResolver, new HashSet<String>()); return parseStringValue(value, placeholderResolver, new HashSet<String>());
} }
protected String parseStringValue(String strVal, PlaceholderResolver placeholderResolver, protected String parseStringValue(
Set<String> visitedPlaceholders) { String strVal, PlaceholderResolver placeholderResolver, Set<String> visitedPlaceholders) {
StringBuilder buf = new StringBuilder(strVal); StringBuilder buf = new StringBuilder(strVal);
int startIndex = strVal.indexOf(this.placeholderPrefix); int startIndex = strVal.indexOf(this.placeholderPrefix);
...@@ -120,14 +122,25 @@ public class PropertyPlaceholderHelper { ...@@ -120,14 +122,25 @@ public class PropertyPlaceholderHelper {
// Now obtain the value for the fully resolved key... // Now obtain the value for the fully resolved key...
String propVal = placeholderResolver.resolvePlaceholder(placeholder); String propVal = placeholderResolver.resolvePlaceholder(placeholder);
if (propVal == null && this.valueSeparator != null) {
int separatorIndex = placeholder.indexOf(this.valueSeparator);
if (separatorIndex != -1) {
String actualPlaceholder = placeholder.substring(0, separatorIndex);
String defaultValue = placeholder.substring(separatorIndex + this.valueSeparator.length());
propVal = placeholderResolver.resolvePlaceholder(actualPlaceholder);
if (propVal == null) {
propVal = defaultValue;
}
}
}
if (propVal != null) { if (propVal != null) {
// Recursive invocation, parsing placeholders contained in the // Recursive invocation, parsing placeholders contained in the
// previously resolved placeholder value. // previously resolved placeholder value.
propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders); propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders);
buf.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal); buf.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal);
if (LOGGER.isTraceEnabled()) { if (logger.isTraceEnabled()) {
LOGGER.trace("Resolved placeholder '" + placeholder + "'"); logger.trace("Resolved placeholder '" + placeholder + "'");
} }
startIndex = buf.indexOf(this.placeholderPrefix, startIndex + propVal.length()); startIndex = buf.indexOf(this.placeholderPrefix, startIndex + propVal.length());
...@@ -174,19 +187,19 @@ public class PropertyPlaceholderHelper { ...@@ -174,19 +187,19 @@ public class PropertyPlaceholderHelper {
return -1; return -1;
} }
/** /**
* Strategy interface used to resolve replacement values for placeholders contained in Strings. * Strategy interface used to resolve replacement values for placeholders contained in Strings.
*
* @see PropertyPlaceholderHelper * @see PropertyPlaceholderHelper
*/ */
public static interface PlaceholderResolver { public static interface PlaceholderResolver {
/** /**
* Resolves the supplied placeholder name into the replacement value. * Resolves the supplied placeholder name into the replacement value.
*
* @param placeholderName the name of the placeholder to resolve. * @param placeholderName the name of the placeholder to resolve.
* @return the replacement value or <code>null</code> if no replacement is to be made. * @return the replacement value or <code>null</code> if no replacement is to be made.
*/ */
String resolvePlaceholder(String placeholderName); String resolvePlaceholder(String placeholderName);
} }
} }
/* /*
* Copyright 2002-2008 the original author or authors. * Copyright 2002-2009 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -38,18 +38,22 @@ public abstract class SystemPropertyUtils { ...@@ -38,18 +38,22 @@ public abstract class SystemPropertyUtils {
/** Suffix for system property placeholders: "}" */ /** Suffix for system property placeholders: "}" */
public static final String PLACEHOLDER_SUFFIX = "}"; public static final String PLACEHOLDER_SUFFIX = "}";
private static final PropertyPlaceholderHelper HELPER = new PropertyPlaceholderHelper(PLACEHOLDER_PREFIX, PLACEHOLDER_SUFFIX); /** Value separator for system property placeholders: "}" */
public static final String VALUE_SEPARATOR = ":";
private static final PropertyPlaceholderHelper helper =
new PropertyPlaceholderHelper(PLACEHOLDER_PREFIX, PLACEHOLDER_SUFFIX, VALUE_SEPARATOR, false);
/** /**
* Resolve ${...} placeholders in the given text, replacing them with corresponding system property values. * Resolve ${...} placeholders in the given text, replacing them with corresponding system property values.
*
* @param text the String to resolve * @param text the String to resolve
* @return the resolved String * @return the resolved String
* @see #PLACEHOLDER_PREFIX * @see #PLACEHOLDER_PREFIX
* @see #PLACEHOLDER_SUFFIX * @see #PLACEHOLDER_SUFFIX
*/ */
public static String resolvePlaceholders(final String text) { public static String resolvePlaceholders(final String text) {
return HELPER.replacePlaceholders(text, new PlaceholderResolver() { return helper.replacePlaceholders(text, new PlaceholderResolver() {
public String resolvePlaceholder(String placeholderName) { public String resolvePlaceholder(String placeholderName) {
String propVal = null; String propVal = null;
try { try {
......
...@@ -18,10 +18,12 @@ package org.springframework.util; ...@@ -18,10 +18,12 @@ package org.springframework.util;
import java.util.Properties; import java.util.Properties;
import static org.junit.Assert.*;
import org.junit.Test; import org.junit.Test;
import static org.junit.Assert.assertEquals;
/** @author Rob Harrop */ /**
* @author Rob Harrop
*/
public class PropertyPlaceholderHelperTests { public class PropertyPlaceholderHelperTests {
private final PropertyPlaceholderHelper helper = new PropertyPlaceholderHelper("${", "}"); private final PropertyPlaceholderHelper helper = new PropertyPlaceholderHelper("${", "}");
...@@ -98,7 +100,8 @@ public class PropertyPlaceholderHelperTests { ...@@ -98,7 +100,8 @@ public class PropertyPlaceholderHelperTests {
Properties props = new Properties(); Properties props = new Properties();
props.setProperty("foo", "bar"); props.setProperty("foo", "bar");
PropertyPlaceholderHelper helper = new PropertyPlaceholderHelper("${", "}", false); PropertyPlaceholderHelper helper = new PropertyPlaceholderHelper("${", "}", null, false);
assertEquals("foo=bar,bar=${bar}", helper.replacePlaceholders(text, props)); assertEquals("foo=bar,bar=${bar}", helper.replacePlaceholders(text, props));
} }
} }
...@@ -18,33 +18,54 @@ package org.springframework.util; ...@@ -18,33 +18,54 @@ package org.springframework.util;
import java.util.Map; import java.util.Map;
import static org.junit.Assert.*;
import org.junit.Test; import org.junit.Test;
import static org.junit.Assert.assertEquals;
/** @author Rob Harrop */ /**
* @author Rob Harrop
* @author Juergen Hoeller
*/
public class SystemPropertyUtilsTests { public class SystemPropertyUtilsTests {
@Test @Test
public void testReplaceFromSystemProperty() { public void testReplaceFromSystemProperty() {
System.setProperty("test.prop", "bar"); System.setProperty("test.prop", "bar");
String resolved = SystemPropertyUtils.resolvePlaceholders("${test.prop}"); try {
assertEquals("bar", resolved); String resolved = SystemPropertyUtils.resolvePlaceholders("${test.prop}");
assertEquals("bar", resolved);
}
finally {
System.getProperties().remove("test.prop");
}
}
@Test
public void testReplaceWithDefault() {
String resolved = SystemPropertyUtils.resolvePlaceholders("${test.prop:foo}");
assertEquals("foo", resolved);
} }
@Test @Test
public void testRecursiveFromSystemProperty() { public void testRecursiveFromSystemProperty() {
System.setProperty("test.prop", "foo=${bar}"); System.setProperty("test.prop", "foo=${bar}");
System.setProperty("bar", "baz"); System.setProperty("bar", "baz");
String resolved = SystemPropertyUtils.resolvePlaceholders("${test.prop}"); try {
assertEquals("foo=baz", resolved); String resolved = SystemPropertyUtils.resolvePlaceholders("${test.prop}");
assertEquals("foo=baz", resolved);
}
finally {
System.getProperties().remove("test.prop");
System.getProperties().remove("bar");
}
} }
@Test @Test
public void testReplaceFromEnv() { public void testReplaceFromEnv() {
Map<String,String> env = System.getenv(); Map<String,String> env = System.getenv();
if(env.containsKey("PATH")) { if (env.containsKey("PATH")) {
String text = "${PATH}"; String text = "${PATH}";
assertEquals(env.get("PATH"), SystemPropertyUtils.resolvePlaceholders(text)); assertEquals(env.get("PATH"), SystemPropertyUtils.resolvePlaceholders(text));
} }
} }
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册