diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/PropertyPlaceholderConfigurer.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/PropertyPlaceholderConfigurer.java index 5c7b570638..0c5a3170e2 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/PropertyPlaceholderConfigurer.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/PropertyPlaceholderConfigurer.java @@ -99,6 +99,9 @@ public class PropertyPlaceholderConfigurer extends PropertyResourceConfigurer /** Default placeholder suffix: "}" */ public static final String DEFAULT_PLACEHOLDER_SUFFIX = "}"; + /** Default value separator: ":" */ + public static final String DEFAULT_VALUE_SEPARATOR = ":"; + /** Never check system properties. */ public static final int SYSTEM_PROPERTIES_MODE_NEVER = 0; @@ -122,6 +125,8 @@ public class PropertyPlaceholderConfigurer extends PropertyResourceConfigurer private String placeholderSuffix = DEFAULT_PLACEHOLDER_SUFFIX; + private String valueSeparator = DEFAULT_VALUE_SEPARATOR; + private int systemPropertiesMode = SYSTEM_PROPERTIES_MODE_FALLBACK; private boolean searchSystemEnvironment = true; @@ -360,7 +365,8 @@ public class PropertyPlaceholderConfigurer extends PropertyResourceConfigurer private final PlaceholderResolver resolver; public PlaceholderResolvingStringValueResolver(Properties props) { - this.helper = new PropertyPlaceholderHelper(placeholderPrefix, placeholderSuffix, ignoreUnresolvablePlaceholders); + this.helper = new PropertyPlaceholderHelper( + placeholderPrefix, placeholderSuffix, valueSeparator, ignoreUnresolvablePlaceholders); this.resolver = new PropertyPlaceholderConfigurerResolver(props); } @@ -370,6 +376,7 @@ public class PropertyPlaceholderConfigurer extends PropertyResourceConfigurer } } + private class PropertyPlaceholderConfigurerResolver implements PlaceholderResolver { private final Properties props; diff --git a/org.springframework.beans/src/test/java/org/springframework/beans/factory/config/PropertyResourceConfigurerTests.java b/org.springframework.beans/src/test/java/org/springframework/beans/factory/config/PropertyResourceConfigurerTests.java index 77ab1e039a..f228985203 100644 --- a/org.springframework.beans/src/test/java/org/springframework/beans/factory/config/PropertyResourceConfigurerTests.java +++ b/org.springframework.beans/src/test/java/org/springframework/beans/factory/config/PropertyResourceConfigurerTests.java @@ -662,6 +662,19 @@ public final class PropertyResourceConfigurerTests { 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 public void testPropertyPlaceholderConfigurerWithAliases() { factory.registerBeanDefinition("tb", diff --git a/org.springframework.core/src/main/java/org/springframework/util/PropertyPlaceholderHelper.java b/org.springframework.core/src/main/java/org/springframework/util/PropertyPlaceholderHelper.java index 4e61033f3f..d0fffbe2c7 100644 --- a/org.springframework.core/src/main/java/org/springframework/util/PropertyPlaceholderHelper.java +++ b/org.springframework.core/src/main/java/org/springframework/util/PropertyPlaceholderHelper.java @@ -16,18 +16,18 @@ package org.springframework.util; +import java.util.HashSet; import java.util.Properties; import java.util.Set; -import java.util.HashSet; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Utility class for working with Strings that have placeholder values in them. A placeholder takes the form - * ${name}. Using PropertyPlaceholderUtils these placeholders can be substituted for - * user-supplied values.

Values for substitution can be supplied using a {@link Properties} instance or using a - * {@link PlaceholderResolver}. + * ${name}. Using PropertyPlaceholderHelper these placeholders can be substituted for + * user-supplied values.

Values for substitution can be supplied using a {@link Properties} instance or + * using a {@link PlaceholderResolver}. * * @author Juergen Hoeller * @author Rob Harrop @@ -35,46 +35,49 @@ import org.apache.commons.logging.LogFactory; */ 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 placeholderSuffix; + private final String valueSeparator; + private final boolean ignoreUnresolvablePlaceholders; + /** - * Creates a new PropertyPlaceholderHelper that uses the supplied prefix and suffix. Unresolvable - * placeholders are ignored. - * + * Creates a new PropertyPlaceholderHelper that uses the supplied prefix and suffix. + * Unresolvable placeholders are ignored. * @param placeholderPrefix the prefix that denotes the start of a placeholder. * @param placeholderSuffix the suffix that denotes the end of a placeholder. */ public PropertyPlaceholderHelper(String placeholderPrefix, String placeholderSuffix) { - this(placeholderPrefix, placeholderSuffix, true); + this(placeholderPrefix, placeholderSuffix, null, true); } /** * Creates a new PropertyPlaceholderHelper that uses the supplied prefix and suffix. - * * @param placeholderPrefix the prefix that denotes the start of a placeholder. * @param placeholderSuffix the suffix that denotes the end of a placeholder. * @param ignoreUnresolvablePlaceholders indicates whether unresolvable placeholders should be ignored * (true) or cause an exception (false). */ public PropertyPlaceholderHelper(String placeholderPrefix, String placeholderSuffix, - boolean ignoreUnresolvablePlaceholders) { - Assert.notNull(placeholderPrefix, "Argument 'placeholderPrefix' must not be null."); - Assert.notNull(placeholderSuffix, "Argument 'placeholderSuffix' must not be null."); + String valueSeparator, boolean ignoreUnresolvablePlaceholders) { + + Assert.notNull(placeholderPrefix, "placeholderPrefix must not be null"); + Assert.notNull(placeholderSuffix, "placeholderSuffix must not be null"); this.placeholderPrefix = placeholderPrefix; this.placeholderSuffix = placeholderSuffix; + this.valueSeparator = valueSeparator; this.ignoreUnresolvablePlaceholders = ignoreUnresolvablePlaceholders; } + /** - * Replaces all placeholders of format ${name} with the corresponding property from the supplied {@link - * Properties}. - * + * Replaces all placeholders of format ${name} with the corresponding property + * from the supplied {@link Properties}. * @param value the value containing the placeholders to be replaced. * @param properties the Properties to use for replacement. * @return the supplied value with placeholders replaced inline. @@ -82,7 +85,6 @@ public class PropertyPlaceholderHelper { public String replacePlaceholders(String value, final Properties properties) { Assert.notNull(properties, "Argument 'properties' must not be null."); return replacePlaceholders(value, new PlaceholderResolver() { - public String resolvePlaceholder(String placeholderName) { return properties.getProperty(placeholderName); } @@ -90,9 +92,8 @@ public class PropertyPlaceholderHelper { } /** - * Replaces all placeholders of format ${name} with the value returned from the supplied {@link - * PlaceholderResolver}. - * + * Replaces all placeholders of format ${name} with the value returned from the supplied + * {@link PlaceholderResolver}. * @param value the value containing the placeholders to be replaced. * @param placeholderResolver the PlaceholderResolver to use for replacement. * @return the supplied value with placeholders replaced inline. @@ -102,8 +103,9 @@ public class PropertyPlaceholderHelper { return parseStringValue(value, placeholderResolver, new HashSet()); } - protected String parseStringValue(String strVal, PlaceholderResolver placeholderResolver, - Set visitedPlaceholders) { + protected String parseStringValue( + String strVal, PlaceholderResolver placeholderResolver, Set visitedPlaceholders) { + StringBuilder buf = new StringBuilder(strVal); int startIndex = strVal.indexOf(this.placeholderPrefix); @@ -120,14 +122,25 @@ public class PropertyPlaceholderHelper { // Now obtain the value for the fully resolved key... 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) { // Recursive invocation, parsing placeholders contained in the // previously resolved placeholder value. propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders); buf.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal); - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Resolved placeholder '" + placeholder + "'"); + if (logger.isTraceEnabled()) { + logger.trace("Resolved placeholder '" + placeholder + "'"); } startIndex = buf.indexOf(this.placeholderPrefix, startIndex + propVal.length()); @@ -174,19 +187,19 @@ public class PropertyPlaceholderHelper { return -1; } + /** * Strategy interface used to resolve replacement values for placeholders contained in Strings. - * * @see PropertyPlaceholderHelper */ public static interface PlaceholderResolver { /** * Resolves the supplied placeholder name into the replacement value. - * * @param placeholderName the name of the placeholder to resolve. * @return the replacement value or null if no replacement is to be made. */ String resolvePlaceholder(String placeholderName); } + } diff --git a/org.springframework.core/src/main/java/org/springframework/util/SystemPropertyUtils.java b/org.springframework.core/src/main/java/org/springframework/util/SystemPropertyUtils.java index 1ae56c1c07..98921aa8c6 100644 --- a/org.springframework.core/src/main/java/org/springframework/util/SystemPropertyUtils.java +++ b/org.springframework.core/src/main/java/org/springframework/util/SystemPropertyUtils.java @@ -1,5 +1,5 @@ /* - * 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"); * you may not use this file except in compliance with the License. @@ -38,18 +38,22 @@ public abstract class SystemPropertyUtils { /** Suffix for system property placeholders: "}" */ 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. - * * @param text the String to resolve * @return the resolved String * @see #PLACEHOLDER_PREFIX * @see #PLACEHOLDER_SUFFIX */ public static String resolvePlaceholders(final String text) { - return HELPER.replacePlaceholders(text, new PlaceholderResolver() { - + return helper.replacePlaceholders(text, new PlaceholderResolver() { public String resolvePlaceholder(String placeholderName) { String propVal = null; try { diff --git a/org.springframework.core/src/test/java/org/springframework/util/PropertyPlaceholderHelperTests.java b/org.springframework.core/src/test/java/org/springframework/util/PropertyPlaceholderHelperTests.java index c4dd9b77cf..b43b2a01c3 100644 --- a/org.springframework.core/src/test/java/org/springframework/util/PropertyPlaceholderHelperTests.java +++ b/org.springframework.core/src/test/java/org/springframework/util/PropertyPlaceholderHelperTests.java @@ -18,10 +18,12 @@ package org.springframework.util; import java.util.Properties; +import static org.junit.Assert.*; import org.junit.Test; -import static org.junit.Assert.assertEquals; -/** @author Rob Harrop */ +/** + * @author Rob Harrop + */ public class PropertyPlaceholderHelperTests { private final PropertyPlaceholderHelper helper = new PropertyPlaceholderHelper("${", "}"); @@ -98,7 +100,8 @@ public class PropertyPlaceholderHelperTests { Properties props = new Properties(); props.setProperty("foo", "bar"); - PropertyPlaceholderHelper helper = new PropertyPlaceholderHelper("${", "}", false); + PropertyPlaceholderHelper helper = new PropertyPlaceholderHelper("${", "}", null, false); assertEquals("foo=bar,bar=${bar}", helper.replacePlaceholders(text, props)); } + } diff --git a/org.springframework.core/src/test/java/org/springframework/util/SystemPropertyUtilsTests.java b/org.springframework.core/src/test/java/org/springframework/util/SystemPropertyUtilsTests.java index e02e2d6a6b..7521be6f3b 100644 --- a/org.springframework.core/src/test/java/org/springframework/util/SystemPropertyUtilsTests.java +++ b/org.springframework.core/src/test/java/org/springframework/util/SystemPropertyUtilsTests.java @@ -18,33 +18,54 @@ package org.springframework.util; import java.util.Map; +import static org.junit.Assert.*; import org.junit.Test; -import static org.junit.Assert.assertEquals; -/** @author Rob Harrop */ +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ public class SystemPropertyUtilsTests { @Test public void testReplaceFromSystemProperty() { System.setProperty("test.prop", "bar"); - String resolved = SystemPropertyUtils.resolvePlaceholders("${test.prop}"); - assertEquals("bar", resolved); + try { + 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 public void testRecursiveFromSystemProperty() { System.setProperty("test.prop", "foo=${bar}"); System.setProperty("bar", "baz"); - String resolved = SystemPropertyUtils.resolvePlaceholders("${test.prop}"); - assertEquals("foo=baz", resolved); + try { + String resolved = SystemPropertyUtils.resolvePlaceholders("${test.prop}"); + assertEquals("foo=baz", resolved); + } + finally { + System.getProperties().remove("test.prop"); + System.getProperties().remove("bar"); + } } @Test public void testReplaceFromEnv() { Map env = System.getenv(); - if(env.containsKey("PATH")) { + if (env.containsKey("PATH")) { String text = "${PATH}"; assertEquals(env.get("PATH"), SystemPropertyUtils.resolvePlaceholders(text)); } } + }