[SPR-6025] support for recursive property placeholder replacement in system properties
git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@1847 50f2f4bb-b051-0410-bef5-90022cba6387
This commit is contained in:
parent
86ccb01bc2
commit
9e864c9343
|
|
@ -17,6 +17,8 @@
|
|||
package org.springframework.util;
|
||||
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
|
||||
/**
|
||||
* Utility class for working with Strings that have placeholder values in them. A placeholder takes the form
|
||||
|
|
@ -63,29 +65,75 @@ public class PropertyPlaceholderUtils {
|
|||
* @return the supplied value with placeholders replaced inline.
|
||||
*/
|
||||
public static String replacePlaceholders(String value, PlaceholderResolver placeholderResolver) {
|
||||
StringBuilder result = new StringBuilder(value);
|
||||
return parseStringValue(value, placeholderResolver, new HashSet<String>());
|
||||
}
|
||||
|
||||
int startIndex = result.indexOf(PLACEHOLDER_PREFIX);
|
||||
protected static String parseStringValue(String strVal, PlaceholderResolver placeholderResolver, Set<String> visitedPlaceholders) {
|
||||
StringBuilder buf = new StringBuilder(strVal);
|
||||
|
||||
int startIndex = strVal.indexOf(PLACEHOLDER_PREFIX);
|
||||
while (startIndex != -1) {
|
||||
int endIndex = result.indexOf(PLACEHOLDER_SUFFIX, startIndex + PLACEHOLDER_PREFIX.length());
|
||||
int endIndex = findPlaceholderEndIndex(buf, startIndex);
|
||||
if (endIndex != -1) {
|
||||
String placeholder = result.substring(startIndex + PLACEHOLDER_PREFIX.length(), endIndex);
|
||||
int nextIndex = endIndex + PLACEHOLDER_SUFFIX.length();
|
||||
String placeholder = buf.substring(startIndex + PLACEHOLDER_PREFIX.length(), endIndex);
|
||||
if (!visitedPlaceholders.add(placeholder)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Circular placeholder reference '" + placeholder + "' in property definitions");
|
||||
}
|
||||
// Recursive invocation, parsing placeholders contained in the placeholder key.
|
||||
placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders);
|
||||
|
||||
// Now obtain the value for the fully resolved key...
|
||||
String propVal = placeholderResolver.resolvePlaceholder(placeholder);
|
||||
if (propVal != null) {
|
||||
result.replace(startIndex, endIndex + PLACEHOLDER_SUFFIX.length(), propVal);
|
||||
nextIndex = startIndex + propVal.length();
|
||||
// Recursive invocation, parsing placeholders contained in the
|
||||
// previously resolved placeholder value.
|
||||
propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders);
|
||||
buf.replace(startIndex, endIndex + PLACEHOLDER_SUFFIX.length(), propVal);
|
||||
|
||||
//if (logger.isTraceEnabled()) {
|
||||
// logger.trace("Resolved placeholder '" + placeholder + "'");
|
||||
//}
|
||||
|
||||
startIndex = buf.indexOf(PLACEHOLDER_PREFIX, startIndex + propVal.length());
|
||||
}
|
||||
else {
|
||||
// Proceed with unprocessed value.
|
||||
startIndex = buf.indexOf(PLACEHOLDER_PREFIX, endIndex + PLACEHOLDER_SUFFIX.length());
|
||||
}
|
||||
|
||||
startIndex = result.indexOf(PLACEHOLDER_PREFIX, nextIndex);
|
||||
visitedPlaceholders.remove(placeholder);
|
||||
}
|
||||
else {
|
||||
startIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return result.toString();
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private static int findPlaceholderEndIndex(CharSequence buf, int startIndex) {
|
||||
int index = startIndex + PLACEHOLDER_PREFIX.length();
|
||||
int withinNestedPlaceholder = 0;
|
||||
while (index < buf.length()) {
|
||||
if (StringUtils.substringMatch(buf, index, PLACEHOLDER_SUFFIX)) {
|
||||
if (withinNestedPlaceholder > 0) {
|
||||
withinNestedPlaceholder--;
|
||||
index = index + PLACEHOLDER_PREFIX.length() - 1;
|
||||
}
|
||||
else {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
else if (StringUtils.substringMatch(buf, index, PLACEHOLDER_PREFIX)) {
|
||||
withinNestedPlaceholder++;
|
||||
index = index + PLACEHOLDER_PREFIX.length();
|
||||
}
|
||||
else {
|
||||
index++;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -16,17 +16,19 @@
|
|||
|
||||
package org.springframework.util;
|
||||
|
||||
import org.springframework.util.PropertyPlaceholderUtils.PlaceholderResolver;
|
||||
|
||||
/**
|
||||
* Helper class for resolving placeholders in texts. Usually applied to file paths.
|
||||
*
|
||||
* <p>A text may contain <code>${...}</code> placeholders, to be resolved as
|
||||
* system properties: e.g. <code>${user.dir}</code>.
|
||||
* <p>A text may contain <code>${...}</code> placeholders, to be resolved as system properties: e.g.
|
||||
* <code>${user.dir}</code>.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2.5
|
||||
* @see #PLACEHOLDER_PREFIX
|
||||
* @see #PLACEHOLDER_SUFFIX
|
||||
* @see System#getProperty(String)
|
||||
* @since 1.2.5
|
||||
*/
|
||||
public abstract class SystemPropertyUtils {
|
||||
|
||||
|
|
@ -36,51 +38,39 @@ public abstract class SystemPropertyUtils {
|
|||
/** Suffix for system property placeholders: "}" */
|
||||
public static final String PLACEHOLDER_SUFFIX = "}";
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @return the resolved String
|
||||
* @see #PLACEHOLDER_PREFIX
|
||||
* @see #PLACEHOLDER_SUFFIX
|
||||
*/
|
||||
public static String resolvePlaceholders(String text) {
|
||||
StringBuilder result = new StringBuilder(text);
|
||||
public static String resolvePlaceholders(final String text) {
|
||||
return PropertyPlaceholderUtils.replacePlaceholders(text, new PlaceholderResolver() {
|
||||
|
||||
int startIndex = result.indexOf(PLACEHOLDER_PREFIX);
|
||||
while (startIndex != -1) {
|
||||
int endIndex = result.indexOf(PLACEHOLDER_SUFFIX, startIndex + PLACEHOLDER_PREFIX.length());
|
||||
if (endIndex != -1) {
|
||||
String placeholder = result.substring(startIndex + PLACEHOLDER_PREFIX.length(), endIndex);
|
||||
int nextIndex = endIndex + PLACEHOLDER_SUFFIX.length();
|
||||
public String resolvePlaceholder(String placeholderName) {
|
||||
String propVal = null;
|
||||
try {
|
||||
String propVal = System.getProperty(placeholder);
|
||||
propVal = System.getProperty(placeholderName);
|
||||
if (propVal == null) {
|
||||
// Fall back to searching the system environment.
|
||||
propVal = System.getenv(placeholder);
|
||||
propVal = System.getenv(placeholderName);
|
||||
}
|
||||
if (propVal != null) {
|
||||
result.replace(startIndex, endIndex + PLACEHOLDER_SUFFIX.length(), propVal);
|
||||
nextIndex = startIndex + propVal.length();
|
||||
}
|
||||
else {
|
||||
System.err.println("Could not resolve placeholder '" + placeholder + "' in [" + text +
|
||||
|
||||
if (propVal == null) {
|
||||
System.err.println("Could not resolve placeholder '" + placeholderName + "' in [" + text +
|
||||
"] as system property: neither system property nor environment variable found");
|
||||
}
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
System.err.println("Could not resolve placeholder '" + placeholder + "' in [" + text +
|
||||
System.err.println("Could not resolve placeholder '" + placeholderName + "' in [" + text +
|
||||
"] as system property: " + ex);
|
||||
}
|
||||
startIndex = result.indexOf(PLACEHOLDER_PREFIX, nextIndex);
|
||||
}
|
||||
else {
|
||||
startIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
return propVal;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,26 @@ public class PropertyPlaceholderUtilsTests {
|
|||
assertEquals("foo=bar,bar=baz", PropertyPlaceholderUtils.replacePlaceholders(text, props));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRecurseInProperty() {
|
||||
String text = "foo=${bar}";
|
||||
Properties props = new Properties();
|
||||
props.setProperty("bar", "${baz}");
|
||||
props.setProperty("baz", "bar");
|
||||
|
||||
assertEquals("foo=bar", PropertyPlaceholderUtils.replacePlaceholders(text, props));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRecurseInPlaceholder() {
|
||||
String text = "foo=${b${inner}}";
|
||||
Properties props = new Properties();
|
||||
props.setProperty("bar", "bar");
|
||||
props.setProperty("inner", "ar");
|
||||
|
||||
assertEquals("foo=bar", PropertyPlaceholderUtils.replacePlaceholders(text, props));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithResolver() {
|
||||
String text = "foo=${foo}";
|
||||
|
|
|
|||
|
|
@ -31,6 +31,14 @@ public class SystemPropertyUtilsTests {
|
|||
assertEquals("bar", 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);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReplaceFromEnv() {
|
||||
Map<String,String> env = System.getenv();
|
||||
|
|
|
|||
Loading…
Reference in New Issue