From 29cb51240e352e64e69cada610fc2c99a3d9e634 Mon Sep 17 00:00:00 2001 From: Keith Donald Date: Thu, 3 Jul 2008 17:23:42 +0000 Subject: [PATCH] bug fixes related to binding and type conversion --- .../binding/convert/ConversionService.java | 15 ++++--- .../convert/converters/ArrayToArray.java | 26 +++++++++++++ .../convert/converters/ArrayToCollection.java | 28 +++++++++++++ .../convert/converters/ObjectToArray.java | 15 +++++++ .../converters/PropertyEditorConverter.java | 15 +++++++ .../convert/converters/ReverseConverter.java | 15 +++++++ .../convert/converters/StringToCharacter.java | 15 +++++++ .../convert/converters/StringToObject.java | 15 +++++++ .../service/DefaultConversionService.java | 28 +------------ .../beanwrapper/BeanWrapperExpression.java | 39 ++++++++++++++++++- .../BeanWrapperExpressionParser.java | 17 +++++++- .../el/DefaultExpressionFactoryUtils.java | 3 +- .../expression/ognl/OgnlExpressionParser.java | 12 ++++++ .../binding/method/MethodInvoker.java | 2 +- ...lderServicesBeanDefinitionParserTests.java | 4 ++ ...owBuilderServicesBeanDefinitionParser.java | 2 +- .../config/FlowExecutorFactoryBean.java | 5 ++- .../FlowRegistryBeanDefinitionParser.java | 2 +- .../core/collection/LocalParameterMap.java | 15 ++++--- .../support/FlowBuilderContextImpl.java | 4 ++ .../DefaultExpressionParserFactory.java | 2 +- .../webflow/mvc/view/AbstractMvcView.java | 3 +- .../test/TestFlowBuilderServicesFactory.java | 2 +- ...lderServicesBeanDefinitionParserTests.java | 4 ++ .../webflow/mvc/view/MvcViewTests.java | 2 + 25 files changed, 242 insertions(+), 48 deletions(-) diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/ConversionService.java b/spring-binding/src/main/java/org/springframework/binding/convert/ConversionService.java index fb924342..1f4d8111 100644 --- a/spring-binding/src/main/java/org/springframework/binding/convert/ConversionService.java +++ b/spring-binding/src/main/java/org/springframework/binding/convert/ConversionService.java @@ -19,8 +19,7 @@ package org.springframework.binding.convert; * A service interface for retrieving type conversion executors. The returned command objects are thread-safe and may be * safely cached for use by client code. * - * Type converters convert from one type to another. They are more generic than formatters, which convert from string to - * object and back. + * Type converters convert from one type to another. * * @author Keith Donald */ @@ -39,13 +38,19 @@ public interface ConversionService { public ConversionExecutor getConversionExecutor(Class sourceClass, Class targetClass) throws ConversionExecutorNotFoundException; + /** + * Return all conversion executors capable of converting from the provided sourceClass. For + * example, ConversionExecutor[] getConversionExecutor(String.class) would return all converters that + * convert from String to some other Object. + * @param sourceClass the source class converting from + * @return the conversion executors that can convert from that source class + */ + public ConversionExecutor[] getConversionExecutors(Class sourceClass); + /** * Lookup a class by it alias. For example, long for java.lang.Long * @param alias the class alias * @return the class, or null if no alias exists */ public Class getClassForAlias(String alias); - - public ConversionExecutor[] getConversionExecutors(Class sourceClass); - } \ No newline at end of file diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/converters/ArrayToArray.java b/spring-binding/src/main/java/org/springframework/binding/convert/converters/ArrayToArray.java index b4b3eef5..68ceb3cc 100644 --- a/spring-binding/src/main/java/org/springframework/binding/convert/converters/ArrayToArray.java +++ b/spring-binding/src/main/java/org/springframework/binding/convert/converters/ArrayToArray.java @@ -1,3 +1,18 @@ +/* + * Copyright 2004-2008 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.springframework.binding.convert.converters; import java.lang.reflect.Array; @@ -5,10 +20,21 @@ import java.lang.reflect.Array; import org.springframework.binding.convert.ConversionExecutor; import org.springframework.binding.convert.ConversionService; +/** + * Special one-way converter that converts from a source array to a target array. Supports type conversion of the + * individual array elements; for example, the ability to convert a String[] to an Integer[]. Mainly used internally by + * {@link ConversionService} implementations. + * + * @author Keith Donald + */ public class ArrayToArray implements Converter { private ConversionService conversionService; + /** + * Creates a new array-to-array converter. + * @param conversionService the service to use to lookup conversion executors for individual array elements + */ public ArrayToArray(ConversionService conversionService) { this.conversionService = conversionService; } diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/converters/ArrayToCollection.java b/spring-binding/src/main/java/org/springframework/binding/convert/converters/ArrayToCollection.java index b02e4b71..374af6f1 100644 --- a/spring-binding/src/main/java/org/springframework/binding/convert/converters/ArrayToCollection.java +++ b/spring-binding/src/main/java/org/springframework/binding/convert/converters/ArrayToCollection.java @@ -1,3 +1,18 @@ +/* + * Copyright 2004-2008 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.springframework.binding.convert.converters; import java.lang.reflect.Array; @@ -16,6 +31,19 @@ import org.springframework.binding.convert.ConversionService; import org.springframework.core.GenericCollectionTypeResolver; import org.springframework.core.JdkVersion; +/** + * Special one-way converter that converts from a source array to a target collection. Supports the selection of an + * "approximate" collection implementation when a target collection interface such as List.class is + * specified. Supports type conversion of array elements when a concrete parameterized collection class is provided, + * such as IntegerList.class. + * + * Note that type erasure prevents arbitrary access to generic collection element type information at runtime, + * preventing the ability to convert elements for collections declared as properties. + * + * Mainly used internally by {@link ConversionService} implementations. + * + * @author Keith Donald + */ public class ArrayToCollection implements TwoWayConverter { private ConversionService conversionService; diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/converters/ObjectToArray.java b/spring-binding/src/main/java/org/springframework/binding/convert/converters/ObjectToArray.java index 092ee654..ee535789 100644 --- a/spring-binding/src/main/java/org/springframework/binding/convert/converters/ObjectToArray.java +++ b/spring-binding/src/main/java/org/springframework/binding/convert/converters/ObjectToArray.java @@ -1,3 +1,18 @@ +/* + * Copyright 2004-2008 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.springframework.binding.convert.converters; import java.lang.reflect.Array; diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/converters/PropertyEditorConverter.java b/spring-binding/src/main/java/org/springframework/binding/convert/converters/PropertyEditorConverter.java index 43424695..3ee95eea 100644 --- a/spring-binding/src/main/java/org/springframework/binding/convert/converters/PropertyEditorConverter.java +++ b/spring-binding/src/main/java/org/springframework/binding/convert/converters/PropertyEditorConverter.java @@ -1,3 +1,18 @@ +/* + * Copyright 2004-2008 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.springframework.binding.convert.converters; import java.beans.PropertyEditor; diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/converters/ReverseConverter.java b/spring-binding/src/main/java/org/springframework/binding/convert/converters/ReverseConverter.java index fd27d24b..74dba631 100644 --- a/spring-binding/src/main/java/org/springframework/binding/convert/converters/ReverseConverter.java +++ b/spring-binding/src/main/java/org/springframework/binding/convert/converters/ReverseConverter.java @@ -1,3 +1,18 @@ +/* + * Copyright 2004-2008 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.springframework.binding.convert.converters; public class ReverseConverter implements Converter { diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToCharacter.java b/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToCharacter.java index c38b5de4..cc282a40 100644 --- a/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToCharacter.java +++ b/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToCharacter.java @@ -1,3 +1,18 @@ +/* + * Copyright 2004-2008 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.springframework.binding.convert.converters; public class StringToCharacter extends StringToObject { diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToObject.java b/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToObject.java index f5e0114f..be358d32 100644 --- a/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToObject.java +++ b/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToObject.java @@ -1,3 +1,18 @@ +/* + * Copyright 2004-2008 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.springframework.binding.convert.converters; public abstract class StringToObject implements TwoWayConverter { diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/service/DefaultConversionService.java b/spring-binding/src/main/java/org/springframework/binding/convert/service/DefaultConversionService.java index c07a54df..16aea55e 100644 --- a/spring-binding/src/main/java/org/springframework/binding/convert/service/DefaultConversionService.java +++ b/spring-binding/src/main/java/org/springframework/binding/convert/service/DefaultConversionService.java @@ -20,14 +20,11 @@ import java.math.BigInteger; import java.util.Date; import java.util.Locale; -import org.springframework.beans.factory.BeanClassLoaderAware; -import org.springframework.binding.convert.ConversionService; import org.springframework.binding.convert.converters.StringToBigDecimal; import org.springframework.binding.convert.converters.StringToBigInteger; import org.springframework.binding.convert.converters.StringToBoolean; import org.springframework.binding.convert.converters.StringToByte; import org.springframework.binding.convert.converters.StringToCharacter; -import org.springframework.binding.convert.converters.StringToClass; import org.springframework.binding.convert.converters.StringToDate; import org.springframework.binding.convert.converters.StringToDouble; import org.springframework.binding.convert.converters.StringToFloat; @@ -37,7 +34,6 @@ import org.springframework.binding.convert.converters.StringToLocale; import org.springframework.binding.convert.converters.StringToLong; import org.springframework.binding.convert.converters.StringToShort; import org.springframework.core.enums.LabeledEnum; -import org.springframework.util.ClassUtils; /** * Default, local implementation of a conversion service. Will automatically register from string converters for @@ -45,14 +41,7 @@ import org.springframework.util.ClassUtils; * * @author Keith Donald */ -public class DefaultConversionService extends GenericConversionService implements BeanClassLoaderAware { - - /** - * A singleton shared instance. Should never be modified. - */ - private static DefaultConversionService SHARED_INSTANCE; - - private ClassLoader classLoader = ClassUtils.getDefaultClassLoader(); +public class DefaultConversionService extends GenericConversionService { /** * Creates a new default conversion service, installing the default converters. @@ -76,7 +65,6 @@ public class DefaultConversionService extends GenericConversionService implement addConverter(new StringToDouble()); addConverter(new StringToBigInteger()); addConverter(new StringToBigDecimal()); - addConverter(new StringToClass(classLoader)); addConverter(new StringToLocale()); addConverter(new StringToDate()); addConverter(new StringToLabeledEnum()); @@ -94,23 +82,9 @@ public class DefaultConversionService extends GenericConversionService implement addAlias("double", Double.class); addAlias("bigInteger", BigInteger.class); addAlias("bigDecimal", BigDecimal.class); - addAlias("class", Class.class); addAlias("locale", Locale.class); addAlias("date", Date.class); addAlias("labeledEnum", LabeledEnum.class); } - public void setBeanClassLoader(ClassLoader classLoader) { - this.classLoader = classLoader; - } - - /** - * Returns the shared {@link DefaultConversionService} instance. - */ - public synchronized static ConversionService getSharedInstance() { - if (SHARED_INSTANCE == null) { - SHARED_INSTANCE = new DefaultConversionService(); - } - return SHARED_INSTANCE; - } } \ No newline at end of file diff --git a/spring-binding/src/main/java/org/springframework/binding/expression/beanwrapper/BeanWrapperExpression.java b/spring-binding/src/main/java/org/springframework/binding/expression/beanwrapper/BeanWrapperExpression.java index 297c00e8..4c3b3b03 100644 --- a/spring-binding/src/main/java/org/springframework/binding/expression/beanwrapper/BeanWrapperExpression.java +++ b/spring-binding/src/main/java/org/springframework/binding/expression/beanwrapper/BeanWrapperExpression.java @@ -1,3 +1,18 @@ +/* + * Copyright 2004-2008 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.springframework.binding.expression.beanwrapper; import java.beans.PropertyEditorSupport; @@ -12,12 +27,34 @@ import org.springframework.binding.expression.EvaluationException; import org.springframework.binding.expression.Expression; import org.springframework.binding.expression.PropertyNotFoundException; +/** + * An expression that delegates to a {@link BeanWrapperImpl bean wrapper} to evaluate or set a property of a context. + * + * Also supports the configuration of a {@link ConversionService} to allow StringToObject type conversion to occur as + * part of setting a property. The StringToObject ConversionExecutors are automatically adapted and registered as + * PropertyEditors. + * + * Mainly exists to take advantage of BeanWrapper's unique property access features as an Expression implementation, + * notably the ability to infer types of generic collections and maps and perform type coersion on collection elements + * when setting values. + * + * Note that Spring's BeanWrapper is not a full-blown EL implementation: it only supports property access, and does not + * support method invocation, arithmetic operations, or logic operations. + * + * @author Keith Donald + */ public class BeanWrapperExpression implements Expression { private String expression; private ConversionService conversionService; + /** + * Creates a new bean wrapper expression. + * @param expression the property expression string + * @param conversionService the conversion service containing converters to use as PropertyEditors for type + * conversion + */ public BeanWrapperExpression(String expression, ConversionService conversionService) { this.expression = expression; this.conversionService = conversionService; @@ -81,7 +118,7 @@ public class BeanWrapperExpression implements Expression { return expression; } - public static class PropertyEditorConverter extends PropertyEditorSupport { + private static class PropertyEditorConverter extends PropertyEditorSupport { private ConversionExecutor converter; diff --git a/spring-binding/src/main/java/org/springframework/binding/expression/beanwrapper/BeanWrapperExpressionParser.java b/spring-binding/src/main/java/org/springframework/binding/expression/beanwrapper/BeanWrapperExpressionParser.java index 0a344249..7ab4a407 100644 --- a/spring-binding/src/main/java/org/springframework/binding/expression/beanwrapper/BeanWrapperExpressionParser.java +++ b/spring-binding/src/main/java/org/springframework/binding/expression/beanwrapper/BeanWrapperExpressionParser.java @@ -15,6 +15,9 @@ */ package org.springframework.binding.expression.beanwrapper; +import org.springframework.beans.BeanWrapperImpl; +import org.springframework.beans.propertyeditors.PropertiesEditor; +import org.springframework.binding.convert.ConversionExecutor; import org.springframework.binding.convert.ConversionService; import org.springframework.binding.expression.Expression; import org.springframework.binding.expression.ParserContext; @@ -22,7 +25,7 @@ import org.springframework.binding.expression.ParserException; import org.springframework.binding.expression.support.AbstractExpressionParser; /** - * An expression parser that parses Ognl expressions. + * An expression parser that parses BeanWrapper property expressions. * * @author Keith Donald */ @@ -30,10 +33,22 @@ public class BeanWrapperExpressionParser extends AbstractExpressionParser { private ConversionService conversionService; + /** + * The conversion service to use to obtain {@link ConversionExecutor conversion executors} that will be adapted to + * {@link PropertiesEditor property editors} for use during a + * {@link BeanWrapperImpl#setPropertyValue(String, Object) set value} call. + * @return the conversion service + */ public ConversionService getConversionService() { return conversionService; } + /** + * Sets the conversion service to use to obtain {@link ConversionExecutor conversion executors} that will be adapted + * to {@link PropertiesEditor property editors} for use during a + * {@link BeanWrapperImpl#setPropertyValue(String, Object) set value} call. + * @param conversionService the conversion service + */ public void setConversionService(ConversionService conversionService) { this.conversionService = conversionService; } diff --git a/spring-binding/src/main/java/org/springframework/binding/expression/el/DefaultExpressionFactoryUtils.java b/spring-binding/src/main/java/org/springframework/binding/expression/el/DefaultExpressionFactoryUtils.java index 0e591c0b..7b3a7e43 100644 --- a/spring-binding/src/main/java/org/springframework/binding/expression/el/DefaultExpressionFactoryUtils.java +++ b/spring-binding/src/main/java/org/springframework/binding/expression/el/DefaultExpressionFactoryUtils.java @@ -44,7 +44,8 @@ public class DefaultExpressionFactoryUtils { public static ExpressionFactory createExpressionFactory() throws IllegalStateException { Class expressionFactoryClass; try { - expressionFactoryClass = ClassUtils.forName(getDefaultExpressionFactoryClassName()); + expressionFactoryClass = ClassUtils.forName(getDefaultExpressionFactoryClassName(), + DefaultExpressionFactoryUtils.class.getClassLoader()); } catch (ClassNotFoundException e) { IllegalStateException ise = new IllegalStateException( "The default ExpressionFactory class '" diff --git a/spring-binding/src/main/java/org/springframework/binding/expression/ognl/OgnlExpressionParser.java b/spring-binding/src/main/java/org/springframework/binding/expression/ognl/OgnlExpressionParser.java index 8a65a421..38c660c8 100644 --- a/spring-binding/src/main/java/org/springframework/binding/expression/ognl/OgnlExpressionParser.java +++ b/spring-binding/src/main/java/org/springframework/binding/expression/ognl/OgnlExpressionParser.java @@ -17,6 +17,8 @@ package org.springframework.binding.expression.ognl; import ognl.Ognl; import ognl.OgnlException; +import ognl.OgnlRuntime; +import ognl.PropertyAccessor; import org.springframework.binding.expression.Expression; import org.springframework.binding.expression.ParserContext; @@ -29,6 +31,16 @@ import org.springframework.binding.expression.support.AbstractExpressionParser; * @author Keith Donald */ public class OgnlExpressionParser extends AbstractExpressionParser { + + /** + * Add a property access strategy for the given class. + * @param clazz the class that contains properties needing access + * @param propertyAccessor the property access strategy + */ + public void addPropertyAccessor(Class clazz, PropertyAccessor propertyAccessor) { + OgnlRuntime.setPropertyAccessor(clazz, propertyAccessor); + } + protected Expression doParseExpression(String expressionString, ParserContext context) throws ParserException { try { return new OgnlExpression(Ognl.parseExpression(expressionString), parseVariableExpressions(context diff --git a/spring-binding/src/main/java/org/springframework/binding/method/MethodInvoker.java b/spring-binding/src/main/java/org/springframework/binding/method/MethodInvoker.java index caaa6a26..49f4dd1c 100644 --- a/spring-binding/src/main/java/org/springframework/binding/method/MethodInvoker.java +++ b/spring-binding/src/main/java/org/springframework/binding/method/MethodInvoker.java @@ -39,7 +39,7 @@ public class MethodInvoker { /** * Conversion service for converting arguments to the necessary type if required. */ - private ConversionService conversionService = DefaultConversionService.getSharedInstance(); + private ConversionService conversionService = new DefaultConversionService(); /** * A cache of invoked bean methods, keyed weakly. diff --git a/spring-faces/src/test/java/org/springframework/faces/config/FacesFlowBuilderServicesBeanDefinitionParserTests.java b/spring-faces/src/test/java/org/springframework/faces/config/FacesFlowBuilderServicesBeanDefinitionParserTests.java index d7f30c90..a6037145 100644 --- a/spring-faces/src/test/java/org/springframework/faces/config/FacesFlowBuilderServicesBeanDefinitionParserTests.java +++ b/spring-faces/src/test/java/org/springframework/faces/config/FacesFlowBuilderServicesBeanDefinitionParserTests.java @@ -76,6 +76,10 @@ public class FacesFlowBuilderServicesBeanDefinitionParserTests extends TestCase throw new UnsupportedOperationException("Auto-generated method stub"); } + public ConversionExecutor[] getConversionExecutors(Class sourceClass) { + throw new UnsupportedOperationException("Auto-generated method stub"); + } + public Class getClassForAlias(String name) throws ConversionExecutionException { throw new UnsupportedOperationException("Auto-generated method stub"); } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/config/FlowBuilderServicesBeanDefinitionParser.java b/spring-webflow/src/main/java/org/springframework/webflow/config/FlowBuilderServicesBeanDefinitionParser.java index 987d47a0..c80ca857 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/config/FlowBuilderServicesBeanDefinitionParser.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/config/FlowBuilderServicesBeanDefinitionParser.java @@ -48,7 +48,7 @@ class FlowBuilderServicesBeanDefinitionParser extends AbstractSingleBeanDefiniti if (StringUtils.hasText(conversionService)) { definitionBuilder.addPropertyReference("conversionService", conversionService); } else { - definitionBuilder.addPropertyValue("conversionService", DefaultConversionService.getSharedInstance()); + definitionBuilder.addPropertyValue("conversionService", new DefaultConversionService()); } } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/config/FlowExecutorFactoryBean.java b/spring-webflow/src/main/java/org/springframework/webflow/config/FlowExecutorFactoryBean.java index 5407e290..177a6991 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/config/FlowExecutorFactoryBean.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/config/FlowExecutorFactoryBean.java @@ -72,7 +72,7 @@ class FlowExecutorFactoryBean implements FactoryBean, ApplicationContextAware, B private FlowExecutionListenerLoader flowExecutionListenerLoader; - private ConversionService conversionService = DefaultConversionService.getSharedInstance(); + private ConversionService conversionService; private FlowExecutor flowExecutor; @@ -137,6 +137,9 @@ class FlowExecutorFactoryBean implements FactoryBean, ApplicationContextAware, B public void afterPropertiesSet() throws Exception { Assert.notNull(flowDefinitionLocator, "The flow definition locator property is required"); + if (conversionService == null) { + conversionService = new DefaultConversionService(); + } MutableAttributeMap executionAttributes = createFlowExecutionAttributes(); FlowExecutionImplFactory executionFactory = createFlowExecutionFactory(executionAttributes); DefaultFlowExecutionRepository executionRepository = createFlowExecutionRepository(executionFactory); diff --git a/spring-webflow/src/main/java/org/springframework/webflow/config/FlowRegistryBeanDefinitionParser.java b/spring-webflow/src/main/java/org/springframework/webflow/config/FlowRegistryBeanDefinitionParser.java index 44fa55d3..769cae74 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/config/FlowRegistryBeanDefinitionParser.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/config/FlowRegistryBeanDefinitionParser.java @@ -126,7 +126,7 @@ class FlowRegistryBeanDefinitionParser extends AbstractSingleBeanDefinitionParse private BeanDefinition createDefaultFlowBuilderServices(ParserContext context) { BeanDefinitionBuilder defaultBuilder = BeanDefinitionBuilder.genericBeanDefinition(FlowBuilderServices.class); - defaultBuilder.addPropertyValue("conversionService", DefaultConversionService.getSharedInstance()); + defaultBuilder.addPropertyValue("conversionService", new DefaultConversionService()); defaultBuilder.addPropertyValue("expressionParser", DefaultExpressionParserFactory.getExpressionParser()); defaultBuilder.addPropertyValue("viewFactoryCreator", BeanDefinitionBuilder.genericBeanDefinition( MvcViewFactoryCreator.class).getBeanDefinition()); diff --git a/spring-webflow/src/main/java/org/springframework/webflow/core/collection/LocalParameterMap.java b/spring-webflow/src/main/java/org/springframework/webflow/core/collection/LocalParameterMap.java index 326682bc..9580f824 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/core/collection/LocalParameterMap.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/core/collection/LocalParameterMap.java @@ -42,6 +42,8 @@ import org.springframework.web.multipart.MultipartFile; */ public class LocalParameterMap implements ParameterMap, Serializable { + private static final DefaultConversionService DEFAULT_CONVERSION_SERVICE = new DefaultConversionService(); + /** * The backing map storing the parameters. */ @@ -65,7 +67,7 @@ public class LocalParameterMap implements ParameterMap, Serializable { * @param parameters the contents of this parameter map */ public LocalParameterMap(Map parameters) { - this(parameters, DefaultConversionService.getSharedInstance()); + this(parameters, DEFAULT_CONVERSION_SERVICE); } /** @@ -192,7 +194,8 @@ public class LocalParameterMap implements ParameterMap, Serializable { return (Number) get(parameterName, targetType); } - public Number getNumber(String parameterName, Class targetType, Number defaultValue) throws ConversionExecutionException { + public Number getNumber(String parameterName, Class targetType, Number defaultValue) + throws ConversionExecutionException { assertAssignableTo(Number.class, targetType); return (Number) get(parameterName, targetType, defaultValue); } @@ -211,7 +214,8 @@ public class LocalParameterMap implements ParameterMap, Serializable { return (Integer) get(parameterName, Integer.class, defaultValue); } - public Integer getRequiredInteger(String parameterName) throws IllegalArgumentException, ConversionExecutionException { + public Integer getRequiredInteger(String parameterName) throws IllegalArgumentException, + ConversionExecutionException { return (Integer) getRequired(parameterName, Integer.class); } @@ -235,7 +239,8 @@ public class LocalParameterMap implements ParameterMap, Serializable { return (Boolean) get(parameterName, Boolean.class, defaultValue); } - public Boolean getRequiredBoolean(String parameterName) throws IllegalArgumentException, ConversionExecutionException { + public Boolean getRequiredBoolean(String parameterName) throws IllegalArgumentException, + ConversionExecutionException { return (Boolean) getRequired(parameterName, Boolean.class); } @@ -305,7 +310,7 @@ public class LocalParameterMap implements ParameterMap, Serializable { private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); parameterAccessor = new MapAccessor(parameters); - conversionService = DefaultConversionService.getSharedInstance(); + conversionService = DEFAULT_CONVERSION_SERVICE; } public String toString() { diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/support/FlowBuilderContextImpl.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/support/FlowBuilderContextImpl.java index aef036f1..15fbb1e2 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/support/FlowBuilderContextImpl.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/support/FlowBuilderContextImpl.java @@ -124,6 +124,10 @@ public class FlowBuilderContextImpl implements FlowBuilderContext { return getFlowBuilderServices().getConversionService().getConversionExecutor(sourceClass, targetClass); } + public ConversionExecutor[] getConversionExecutors(Class sourceClass) { + return getFlowBuilderServices().getConversionService().getConversionExecutors(sourceClass); + } + public Class getClassForAlias(String name) { return getFlowBuilderServices().getConversionService().getClassForAlias(name); } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/expression/DefaultExpressionParserFactory.java b/spring-webflow/src/main/java/org/springframework/webflow/expression/DefaultExpressionParserFactory.java index a66f44b4..58be76a9 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/expression/DefaultExpressionParserFactory.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/expression/DefaultExpressionParserFactory.java @@ -94,7 +94,7 @@ public final class DefaultExpressionParserFactory { return new WebFlowELExpressionParser(elFactory); } catch (Exception e) { try { - ClassUtils.forName("ognl.Ognl"); + ClassUtils.forName("ognl.Ognl", DefaultExpressionParserFactory.class.getClassLoader()); return new WebFlowOgnlExpressionParser(); } catch (ClassNotFoundException ex) { IllegalStateException ise = new IllegalStateException( diff --git a/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/AbstractMvcView.java b/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/AbstractMvcView.java index e3d7b184..e03072fc 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/AbstractMvcView.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/AbstractMvcView.java @@ -28,7 +28,6 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.BeanFactory; import org.springframework.binding.convert.ConversionService; -import org.springframework.binding.convert.service.DefaultConversionService; import org.springframework.binding.expression.EvaluationException; import org.springframework.binding.expression.Expression; import org.springframework.binding.expression.ExpressionParser; @@ -77,7 +76,7 @@ public abstract class AbstractMvcView implements View { private ExpressionParser expressionParser = DefaultExpressionParserFactory.getExpressionParser(); - private ConversionService conversionService = DefaultConversionService.getSharedInstance(); + private ConversionService conversionService; private MappingResults mappingResults; diff --git a/spring-webflow/src/main/java/org/springframework/webflow/test/TestFlowBuilderServicesFactory.java b/spring-webflow/src/main/java/org/springframework/webflow/test/TestFlowBuilderServicesFactory.java index 4000c1d1..4417f490 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/test/TestFlowBuilderServicesFactory.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/test/TestFlowBuilderServicesFactory.java @@ -16,7 +16,7 @@ public class TestFlowBuilderServicesFactory { public static FlowBuilderServices getServices() { FlowBuilderServices services = new FlowBuilderServices(); services.setViewFactoryCreator(new MockViewFactoryCreator()); - services.setConversionService(DefaultConversionService.getSharedInstance()); + services.setConversionService(new DefaultConversionService()); services.setExpressionParser(DefaultExpressionParserFactory.getExpressionParser()); services.setApplicationContext(createTestApplicationContext()); return services; diff --git a/spring-webflow/src/test/java/org/springframework/webflow/config/FlowBuilderServicesBeanDefinitionParserTests.java b/spring-webflow/src/test/java/org/springframework/webflow/config/FlowBuilderServicesBeanDefinitionParserTests.java index 48315a78..8b017c9b 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/config/FlowBuilderServicesBeanDefinitionParserTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/config/FlowBuilderServicesBeanDefinitionParserTests.java @@ -59,6 +59,10 @@ public class FlowBuilderServicesBeanDefinitionParserTests extends TestCase { throw new UnsupportedOperationException("Auto-generated method stub"); } + public ConversionExecutor[] getConversionExecutors(Class sourceClass) { + throw new UnsupportedOperationException("Auto-generated method stub"); + } + public Class getClassForAlias(String alias) throws ConversionExecutionException { throw new UnsupportedOperationException("Auto-generated method stub"); } diff --git a/spring-webflow/src/test/java/org/springframework/webflow/mvc/view/MvcViewTests.java b/spring-webflow/src/test/java/org/springframework/webflow/mvc/view/MvcViewTests.java index dfbfd948..7b74cdd0 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/mvc/view/MvcViewTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/mvc/view/MvcViewTests.java @@ -12,6 +12,7 @@ import javax.servlet.http.HttpServletResponse; import junit.framework.TestCase; +import org.springframework.binding.convert.service.DefaultConversionService; import org.springframework.binding.expression.support.StaticExpression; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; @@ -106,6 +107,7 @@ public class MvcViewTests extends TestCase { context.getMockFlowExecutionContext().setKey(new MockFlowExecutionKey("c1v1")); org.springframework.web.servlet.View mvcView = new MockView(); AbstractMvcView view = new MockMvcView(mvcView, context); + view.setConversionService(new DefaultConversionService()); view.render(); assertEquals(context.getFlowScope().get("bindBean"), model.get("bindBean")); BindingModel bm = (BindingModel) model.get(BindingResult.MODEL_KEY_PREFIX + "bindBean");