From eb44c0d493571d81d9aa5a86ac32a3f1d9dfc8ae Mon Sep 17 00:00:00 2001 From: dsyer Date: Sat, 28 Feb 2009 12:01:58 +0000 Subject: [PATCH] BATCH-1107: add PropertyEditor support to placeholder resolution to deal with Dates --- spring-batch-core/pom.xml | 1 + .../scope/util/PlaceholderTargetSource.java | 60 ++++++++++++++++--- .../util/PlaceholderTargetSourceTests.java | 27 ++++++++- .../PlaceholderTargetSourceTests-context.xml | 14 ++++- spring-batch-infrastructure/pom.xml | 1 + spring-batch-test/pom.xml | 3 +- 6 files changed, 94 insertions(+), 12 deletions(-) diff --git a/spring-batch-core/pom.xml b/spring-batch-core/pom.xml index f0cef18cb..cb201d82e 100644 --- a/spring-batch-core/pom.xml +++ b/spring-batch-core/pom.xml @@ -310,6 +310,7 @@ org.codehaus.mojo emma-maven-plugin + 1.0-alpha-1 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 7373d58bb..28092993d 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 @@ -15,11 +15,15 @@ */ package org.springframework.batch.core.scope.util; +import java.beans.PropertyEditor; +import java.util.Date; + import org.springframework.aop.TargetSource; import org.springframework.aop.target.SimpleBeanTargetSource; import org.springframework.beans.BeanWrapper; import org.springframework.beans.BeanWrapperImpl; import org.springframework.beans.BeansException; +import org.springframework.beans.PropertyEditorRegistrySupport; import org.springframework.beans.TypeConverter; import org.springframework.beans.TypeMismatchException; import org.springframework.beans.factory.InitializingBean; @@ -93,7 +97,7 @@ public class PlaceholderTargetSource extends SimpleBeanTargetSource implements I DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(listableBeanFactory); beanFactory.copyConfigurationFrom(listableBeanFactory); - beanFactory.setTypeConverter(new TypeConverter() { + final TypeConverter contextTypeConverter = new TypeConverter() { @SuppressWarnings("unchecked") public Object convertIfNecessary(Object value, Class requiredType, MethodParameter methodParam) throws TypeMismatchException { @@ -105,6 +109,39 @@ public class PlaceholderTargetSource extends SimpleBeanTargetSource implements I result = convertFromContext(key, requiredType); } } + else if (requiredType.isAssignableFrom(value.getClass())) { + result = value; + } + else if (requiredType.isAssignableFrom(String.class)) { + if (typeConverter instanceof PropertyEditorRegistrySupport) { + /* + * PropertyEditorRegistrySupport is de rigeur with + * TypeConverter instances used internally by Spring. If + * we have one of those then we can convert to String + * but the TypeConverter doesn't know how to. + */ + PropertyEditorRegistrySupport registry = (PropertyEditorRegistrySupport) typeConverter; + PropertyEditor editor = registry.findCustomEditor(value.getClass(), null); + if (editor != null) { + if (registry.isSharedEditor(editor)) { + // Synchronized access to shared editor + // instance. + synchronized (editor) { + editor.setValue(value); + result = editor.getAsText(); + } + } + else { + editor.setValue(value); + result = editor.getAsText(); + } + } + } + if (result == null) { + logger.debug("Falling back on toString for conversion of : [" + value.getClass() + "]"); + result = value.toString(); + } + } return result != null ? result : typeConverter.convertIfNecessary(value, requiredType, methodParam); } @@ -112,7 +149,8 @@ public class PlaceholderTargetSource extends SimpleBeanTargetSource implements I public Object convertIfNecessary(Object value, Class requiredType) throws TypeMismatchException { return convertIfNecessary(value, requiredType, null); } - }); + }; + beanFactory.setTypeConverter(contextTypeConverter); String beanName = getTargetBeanName() + "#" + contextFactory.getContextId(); @@ -133,7 +171,16 @@ public class PlaceholderTargetSource extends SimpleBeanTargetSource implements I if (!strVal.contains(PLACEHOLDER_PREFIX)) { return strVal; } - return replacePlaceholders(strVal, typeConverter); + if (strVal.startsWith(PLACEHOLDER_PREFIX) && strVal.endsWith(PLACEHOLDER_SUFFIX)) { + // If the whole value is a placeholder it might be + // possible to replace it all in one go as a String + // (e.g. if it's a ref=#{}) + StringBuilder result = new StringBuilder(strVal); + String key = extractKey(strVal); + replaceIfTypeMatches(result, 0, strVal.length() - 1, key, String.class, typeConverter); + return result.toString(); + } + return replacePlaceholders(strVal, contextTypeConverter); } }) { protected Object resolveValue(Object value) { @@ -216,10 +263,9 @@ public class PlaceholderTargetSource extends SimpleBeanTargetSource implements I replaceIfTypeMatches(result, first, next, key, Integer.class, typeConverter); // Spring cannot convert from String to Date, so there is an error // here. - // replaceIfTypeMatches(result, first, next, key, Date.class, - // typeConverter); - first = result.indexOf(PLACEHOLDER_PREFIX, first + 1);; - next = result.indexOf(PLACEHOLDER_SUFFIX, first + 1);; + replaceIfTypeMatches(result, first, next, key, Date.class, typeConverter); + first = result.indexOf(PLACEHOLDER_PREFIX, first + 1); + next = result.indexOf(PLACEHOLDER_SUFFIX, first + 1); } diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/scope/util/PlaceholderTargetSourceTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/scope/util/PlaceholderTargetSourceTests.java index 84702280b..afcd8389e 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/scope/util/PlaceholderTargetSourceTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/scope/util/PlaceholderTargetSourceTests.java @@ -38,6 +38,10 @@ public class PlaceholderTargetSourceTests extends ContextFactorySupport { @Qualifier("withMultiple") private PlaceholderTargetSource withMultiple; + @Autowired + @Qualifier("withEmbeddedDate") + private PlaceholderTargetSource withEmbeddedDate; + @Autowired @Qualifier("withDate") private PlaceholderTargetSource withDate; @@ -60,7 +64,7 @@ public class PlaceholderTargetSourceTests extends ContextFactorySupport { private Map map = Collections.singletonMap("foo.foo", (Object) "bar"); - private Date date = new Date(); + private Date date = new Date(0L); public Object getContext() { return this; @@ -154,11 +158,16 @@ public class PlaceholderTargetSourceTests extends ContextFactorySupport { assertEquals("bar-4321-4321", target.getName()); } + @Test + public void testGetEmbeddedDate() { + Node target = (Node) withEmbeddedDate.getTarget(); + assertEquals("bar-1970/01/01", target.getName()); + } + @Test public void testGetDate() { Node target = (Node) withDate.getTarget(); - // Remains unconverted because Spring cannot convert from Date to String - assertEquals("bar-#{date}", target.getName()); + assertEquals(0L, target.getDate().getTime()); } @Test @@ -171,6 +180,8 @@ public class PlaceholderTargetSourceTests extends ContextFactorySupport { public static interface Node { String getName(); + Date getDate(); + Node getParent(); } @@ -178,6 +189,8 @@ public class PlaceholderTargetSourceTests extends ContextFactorySupport { private String name; + private Date date; + private Node parent; public Foo() { @@ -191,6 +204,14 @@ public class PlaceholderTargetSourceTests extends ContextFactorySupport { return name; } + public Date getDate() { + return date; + } + + public void setDate(Date date) { + this.date = date; + } + public void setName(String name) { this.name = name; } diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/scope/util/PlaceholderTargetSourceTests-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/scope/util/PlaceholderTargetSourceTests-context.xml index 2423d4e35..6e4089230 100644 --- a/spring-batch-core/src/test/resources/org/springframework/batch/core/scope/util/PlaceholderTargetSourceTests-context.xml +++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/scope/util/PlaceholderTargetSourceTests-context.xml @@ -60,6 +60,12 @@ + + + + + @@ -110,12 +116,18 @@ - + + + + diff --git a/spring-batch-infrastructure/pom.xml b/spring-batch-infrastructure/pom.xml index 0d24a521d..998afcc4a 100644 --- a/spring-batch-infrastructure/pom.xml +++ b/spring-batch-infrastructure/pom.xml @@ -167,6 +167,7 @@ org.codehaus.mojo emma-maven-plugin + 1.0-alpha-1 diff --git a/spring-batch-test/pom.xml b/spring-batch-test/pom.xml index 0cad6a466..22370f3bc 100755 --- a/spring-batch-test/pom.xml +++ b/spring-batch-test/pom.xml @@ -78,8 +78,9 @@ org.codehaus.mojo emma-maven-plugin + 1.0-alpha-1 - \ No newline at end of file +