diff --git a/org.springframework.core/.classpath b/org.springframework.core/.classpath
index dc1edd94f23..72121a37113 100644
--- a/org.springframework.core/.classpath
+++ b/org.springframework.core/.classpath
@@ -11,6 +11,7 @@
+
diff --git a/org.springframework.core/ivy.xml b/org.springframework.core/ivy.xml
index 0538fed5e31..a092dae401c 100644
--- a/org.springframework.core/ivy.xml
+++ b/org.springframework.core/ivy.xml
@@ -32,6 +32,7 @@
+
diff --git a/org.springframework.core/src/main/java/org/springframework/core/env/PropertySourcesPropertyResolver.java b/org.springframework.core/src/main/java/org/springframework/core/env/PropertySourcesPropertyResolver.java
index 333056f3cbf..ceb60f1efd5 100644
--- a/org.springframework.core/src/main/java/org/springframework/core/env/PropertySourcesPropertyResolver.java
+++ b/org.springframework.core/src/main/java/org/springframework/core/env/PropertySourcesPropertyResolver.java
@@ -1,11 +1,11 @@
/*
- * 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.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -72,6 +72,9 @@ public class PropertySourcesPropertyResolver extends AbstractPropertyResolver {
Object value;
if ((value = propertySource.getProperty(key)) != null) {
Class> valueType = value.getClass();
+ if (String.class.equals(valueType)) {
+ value = this.resolveRequiredPlaceholders((String) value);
+ }
if (debugEnabled) {
logger.debug(
format("Found key '%s' in [%s] with type [%s] and value '%s'",
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 4b1b2c37b12..6598f7ce8cd 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
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2010 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.
@@ -170,7 +170,8 @@ public class PropertyPlaceholderHelper {
startIndex = buf.indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.length());
}
else {
- throw new IllegalArgumentException("Could not resolve placeholder '" + placeholder + "'");
+ throw new IllegalArgumentException("Could not resolve placeholder '" +
+ placeholder + "'" + " in string value [" + strVal + "]");
}
visitedPlaceholders.remove(placeholder);
diff --git a/org.springframework.core/src/test/java/org/springframework/core/env/PropertySourcesPropertyResolverTests.java b/org.springframework.core/src/test/java/org/springframework/core/env/PropertySourcesPropertyResolverTests.java
index 4d02d12ef45..c51fd358c82 100644
--- a/org.springframework.core/src/test/java/org/springframework/core/env/PropertySourcesPropertyResolverTests.java
+++ b/org.springframework.core/src/test/java/org/springframework/core/env/PropertySourcesPropertyResolverTests.java
@@ -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.
@@ -16,22 +16,20 @@
package org.springframework.core.env;
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.nullValue;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
+import org.hamcrest.Matchers;
import org.junit.Before;
import org.junit.Test;
+
import org.springframework.core.convert.ConversionException;
import org.springframework.mock.env.MockPropertySource;
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.*;
+
/**
* Unit tests for {@link PropertySourcesPropertyResolver}.
*
@@ -352,6 +350,39 @@ public class PropertySourcesPropertyResolverTests {
propertyResolver.validateRequiredProperties();
}
+ @Test
+ public void resolveNestedPropertyPlaceholders() {
+ MutablePropertySources ps = new MutablePropertySources();
+ ps.addFirst(new MockPropertySource()
+ .withProperty("p1", "v1")
+ .withProperty("p2", "v2")
+ .withProperty("p3", "${p1}:${p2}") // nested placeholders
+ .withProperty("p4", "${p3}") // deeply nested placeholders
+ .withProperty("p5", "${p1}:${p2}:${bogus}") // unresolvable placeholder
+ .withProperty("p6", "${p1}:${p2}:${bogus:def}") // unresolvable w/ default
+ .withProperty("pL", "${pR}") // cyclic reference left
+ .withProperty("pR", "${pL}") // cyclic reference right
+ );
+ PropertySourcesPropertyResolver pr = new PropertySourcesPropertyResolver(ps);
+ assertThat(pr.getProperty("p1"), equalTo("v1"));
+ assertThat(pr.getProperty("p2"), equalTo("v2"));
+ assertThat(pr.getProperty("p3"), equalTo("v1:v2"));
+ assertThat(pr.getProperty("p4"), equalTo("v1:v2"));
+ try {
+ pr.getProperty("p5");
+ } catch (IllegalArgumentException ex) {
+ assertThat(ex.getMessage(), Matchers.containsString(
+ "Could not resolve placeholder 'bogus' in string value [${p1}:${p2}:${bogus}]"));
+ }
+ assertThat(pr.getProperty("p6"), equalTo("v1:v2:def"));
+ try {
+ pr.getProperty("pL");
+ } catch (StackOverflowError ex) {
+ // no explicit handling for cyclic references for now
+ }
+ }
+
+
static interface SomeType { }
static class SpecificType implements SomeType { }
}