diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/scope/util/PlaceholderTargetSource.java b/spring-batch-core/src/main/java/org/springframework/batch/core/scope/util/PlaceholderTargetSource.java index 9d0cc2403..592434f39 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/scope/util/PlaceholderTargetSource.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/scope/util/PlaceholderTargetSource.java @@ -17,6 +17,9 @@ package org.springframework.batch.core.scope.util; import java.beans.PropertyEditor; import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Set; import org.springframework.aop.TargetSource; import org.springframework.aop.target.SimpleBeanTargetSource; @@ -31,6 +34,9 @@ import org.springframework.beans.factory.config.BeanDefinitionVisitor; import org.springframework.beans.factory.config.TypedStringValue; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.GenericBeanDefinition; +import org.springframework.beans.factory.support.ManagedList; +import org.springframework.beans.factory.support.ManagedMap; +import org.springframework.beans.factory.support.ManagedSet; import org.springframework.core.AttributeAccessor; import org.springframework.core.MethodParameter; import org.springframework.util.Assert; @@ -259,7 +265,11 @@ public class PlaceholderTargetSource extends SimpleBeanTargetSource implements I } private Object getPropertyFromContext(String key) { - BeanWrapper wrapper = new BeanWrapperImpl(contextFactory.getContext()); + Object context = contextFactory.getContext(); + if (context==null) { + throw new IllegalStateException("No context available while replacing placeholders."); + } + BeanWrapper wrapper = new BeanWrapperImpl(context); if (wrapper.isReadableProperty(key)) { return wrapper.getPropertyValue(key); } @@ -297,6 +307,7 @@ public class PlaceholderTargetSource extends SimpleBeanTargetSource implements I super(new PlaceholderStringValueResolver(typeConverter)); } + @SuppressWarnings("unchecked") protected Object resolveValue(Object value) { if (value instanceof TypedStringValue) { @@ -304,21 +315,49 @@ public class PlaceholderTargetSource extends SimpleBeanTargetSource implements I TypedStringValue typedStringValue = (TypedStringValue) value; String stringValue = typedStringValue.getValue(); if (stringValue != null) { - - // If the value is a whole key, try to simply replace it from context. + + // If the value is a whole key, try to simply replace it + // from context. if (isKey(stringValue)) { - Object result = getPropertyFromContext(extractKey(stringValue)); + String key = extractKey(stringValue); + Object result = getPropertyFromContext(key); if (result != null) { value = result; + logger.debug(String.format("Resolved %%{%s} to obtain [%s]", key, result)); } } else { - // Otherwise it might contain embedded keys so we try to replace those + // Otherwise it might contain embedded keys so we try to + // replace those String visitedString = resolveStringValue(stringValue); typedStringValue.setValue(visitedString); } } + } else if (value instanceof Map) { + + Map map = (Map) value; + Map newValue = new ManagedMap(map.size()); + newValue.putAll(map); + super.visitMap(newValue); + value = newValue; + + } else if (value instanceof List) { + + List list = (List) value; + List newValue = new ManagedList(list.size()); + newValue.addAll(list); + super.visitList(newValue); + value = newValue; + + } else if (value instanceof Set) { + + Set list = (Set) value; + Set newValue = new ManagedSet(list.size()); + newValue.addAll(list); + super.visitSet(newValue); + value = newValue; + } else { diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/scope/util/MultipleContextPlaceholderTargetSourceTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/scope/util/MultipleContextPlaceholderTargetSourceTests.java index 81d661845..82b6c17cb 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/scope/util/MultipleContextPlaceholderTargetSourceTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/scope/util/MultipleContextPlaceholderTargetSourceTests.java @@ -19,6 +19,7 @@ import static org.junit.Assert.assertEquals; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -56,6 +57,10 @@ public class MultipleContextPlaceholderTargetSourceTests { @Qualifier("list") private TestBean list; + @Autowired + @Qualifier("map") + private TestBean map; + @After public void removeContext() { contextFactory.clearContext(); @@ -100,6 +105,23 @@ public class MultipleContextPlaceholderTargetSourceTests { } + @Test + public void testMultipleValueInMap() throws Exception { + + for (int i = 0; i < 4; i++) { + final String value = "foo" + i; + contextFactory.setContext(this); + attributes = Collections.singletonMap("foo", value); + try { + assertEquals("foo" + i, map.getMap().get("foo")); + } + finally { + contextFactory.clearContext(); + } + } + + } + @Override public String toString() { return "Test context: attributes=" + attributes; @@ -110,6 +132,8 @@ public class MultipleContextPlaceholderTargetSourceTests { private List names = new ArrayList(); + private Map map = new HashMap(); + public String getName() { return name; } @@ -125,6 +149,15 @@ public class MultipleContextPlaceholderTargetSourceTests { public void setNames(List names) { this.names.addAll(names); } + + public Map getMap() { + return new HashMap(map); + } + + public void setMap(Map map) { + this.map.putAll(map); + } + } public static class SimpleContextFactory extends ContextFactorySupport { diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/scope/util/MultipleContextPlaceholderTargetSourceTests-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/scope/util/MultipleContextPlaceholderTargetSourceTests-context.xml index 61c0e9ab4..30e331586 100644 --- a/spring-batch-core/src/test/resources/org/springframework/batch/core/scope/util/MultipleContextPlaceholderTargetSourceTests-context.xml +++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/scope/util/MultipleContextPlaceholderTargetSourceTests-context.xml @@ -26,12 +26,36 @@ - + + + + + + + + + + - - + + + + %{attributes[foo]} + + + + + + + + +