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 32cbb227..0a1adb64 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 @@ -39,4 +39,12 @@ public interface ConversionService { public ConversionExecutor getConversionExecutor(Class sourceClass, Class targetClass) throws ConversionExecutorNotFoundException; + /** + * Lookup a class by its fully qualified name or alias. As an example, for Long.class the fully qualified class name + * is java.lang.Long and the alias is long. + * @param name the fully qualified class name or alias + * @return the class + */ + public Class getClassByName(String name); + } \ No newline at end of file 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 177b4859..bce4f67b 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 @@ -15,6 +15,10 @@ */ package org.springframework.binding.convert.service; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Date; + import org.springframework.binding.convert.ConversionService; import org.springframework.binding.convert.converters.StringToBigDecimal; import org.springframework.binding.convert.converters.StringToBigInteger; @@ -29,6 +33,7 @@ import org.springframework.binding.convert.converters.StringToInteger; import org.springframework.binding.convert.converters.StringToLabeledEnum; import org.springframework.binding.convert.converters.StringToLong; import org.springframework.binding.convert.converters.StringToShort; +import org.springframework.core.enums.LabeledEnum; /** * Default, local implementation of a conversion service. Will automatically register from string converters for @@ -48,6 +53,7 @@ public class DefaultConversionService extends GenericConversionService { */ public DefaultConversionService() { addDefaultConverters(); + addDefaultAliases(); } /** @@ -69,6 +75,23 @@ public class DefaultConversionService extends GenericConversionService { addConverter(new StringToDate()); } + protected void addDefaultAliases() { + addAlias("byte", Byte.class); + addAlias("boolean", Boolean.class); + addAlias("character", Character.class); + addAlias("short", Short.class); + addAlias("integer", Integer.class); + addAlias("long", Long.class); + addAlias("float", Float.class); + addAlias("double", Double.class); + addAlias("bigInteger", BigInteger.class); + addAlias("bigDecimal", BigDecimal.class); + addAlias("class", Class.class); + addAlias("labeledEnum", LabeledEnum.class); + addAlias("date", Date.class); + addAlias("string", String.class); + } + /** * Returns the shared {@link DefaultConversionService} instance. */ diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/service/GenericConversionService.java b/spring-binding/src/main/java/org/springframework/binding/convert/service/GenericConversionService.java index d4b52a8b..cd5a88ef 100644 --- a/spring-binding/src/main/java/org/springframework/binding/convert/service/GenericConversionService.java +++ b/spring-binding/src/main/java/org/springframework/binding/convert/service/GenericConversionService.java @@ -32,6 +32,7 @@ import org.springframework.binding.convert.converters.ObjectToArray; import org.springframework.binding.convert.converters.ReverseConverter; import org.springframework.binding.convert.converters.TwoWayConverter; import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; /** * Base implementation of a conversion service. Initially empty, e.g. no converters are registered by default. @@ -47,6 +48,11 @@ public class GenericConversionService implements ConversionService { */ private final Map sourceClassConverters = new HashMap(); + /** + * Indexes classes by well-known aliases. + */ + private final Map aliasMap = new HashMap(); + /** * An optional parent conversion service. */ @@ -89,6 +95,13 @@ public class GenericConversionService implements ConversionService { } } + /** + * Add an alias for given target type. + */ + public void addAlias(String alias, Class targetType) { + aliasMap.put(alias, targetType); + } + private Map getSourceMap(Class sourceClass) { Map sourceMap = (Map) sourceClassConverters.get(sourceClass); if (sourceMap == null) { @@ -147,6 +160,26 @@ public class GenericConversionService implements ConversionService { } } + public Class getClassByName(String name) throws IllegalArgumentException { + Class clazz = (Class) aliasMap.get(name); + if (clazz != null) { + return clazz; + } else { + if (parent != null) { + return parent.getClassByName(name); + } else { + try { + return ClassUtils.forName(name); + } catch (ClassNotFoundException e) { + IllegalArgumentException iae = new IllegalArgumentException( + "No Class alias or instance found with name '" + name + "' in this ConversionService"); + iae.initCause(e); + throw iae; + } + } + } + } + // subclassing support /** diff --git a/spring-faces/src/main/java/org/springframework/faces/model/converter/FacesConversionService.java b/spring-faces/src/main/java/org/springframework/faces/model/converter/FacesConversionService.java index 6c292f17..1b531291 100644 --- a/spring-faces/src/main/java/org/springframework/faces/model/converter/FacesConversionService.java +++ b/spring-faces/src/main/java/org/springframework/faces/model/converter/FacesConversionService.java @@ -12,6 +12,8 @@ e.org/licenses/LICENSE-2.0 */ package org.springframework.faces.model.converter; +import javax.faces.model.DataModel; + import org.springframework.binding.convert.ConversionService; import org.springframework.binding.convert.service.DefaultConversionService; import org.springframework.faces.model.OneSelectionTrackingListDataModel; @@ -35,5 +37,6 @@ public class FacesConversionService extends DefaultConversionService { protected void addFacesConverters() { addConverter(new DataModelConverter()); + addAlias("dataModel", DataModel.class); } } 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 8c5d4d77..9de063f0 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 @@ -71,24 +71,13 @@ public class FacesFlowBuilderServicesBeanDefinitionParserTests extends TestCase public static class TestConversionService implements ConversionService { - public Class getClassByAlias(String alias) throws ConversionExecutionException { - throw new UnsupportedOperationException("Auto-generated method stub"); - } - public ConversionExecutor getConversionExecutor(Class sourceClass, Class targetClass) throws ConversionExecutionException { throw new UnsupportedOperationException("Auto-generated method stub"); } - public ConversionExecutor getConversionExecutorByTargetAlias(Class sourceClass, String targetAlias) - throws ConversionExecutionException { + public Class getClassByName(String name) throws ConversionExecutionException { throw new UnsupportedOperationException("Auto-generated method stub"); } - - public ConversionExecutor[] getConversionExecutorsForSource(Class sourceClass) - throws ConversionExecutionException { - throw new UnsupportedOperationException("Auto-generated method stub"); - } - } } 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 0080b53f..df5682c7 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 @@ -218,7 +218,7 @@ class FlowExecutorFactoryBean implements FactoryBean, ApplicationContextAware, I } } - private Class fromStringToClass(String type) { - return (Class) conversionService.getConversionExecutor(String.class, Class.class).execute(type); + private Class fromStringToClass(String name) { + return conversionService.getClassByName(name); } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/config/FlowRegistryFactoryBean.java b/spring-webflow/src/main/java/org/springframework/webflow/config/FlowRegistryFactoryBean.java index b1a8f4d6..c4097f08 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/config/FlowRegistryFactoryBean.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/config/FlowRegistryFactoryBean.java @@ -237,8 +237,7 @@ class FlowRegistryFactoryBean implements FactoryBean, InitializingBean { } private Class fromStringToClass(String type) { - return (Class) flowBuilderServices.getConversionService().getConversionExecutor(String.class, Class.class) - .execute(type); + return flowBuilderServices.getConversionService().getClassByName(type); } private FlowDefinition buildFlowDefinition(FlowBuilderInfo builderInfo) { diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/model/FlowModelFlowBuilder.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/model/FlowModelFlowBuilder.java index fbfbaef0..e164acbf 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/model/FlowModelFlowBuilder.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/model/FlowModelFlowBuilder.java @@ -375,7 +375,7 @@ public class FlowModelFlowBuilder extends AbstractFlowBuilder { } private FlowVariable parseFlowVariable(VarModel var) { - Class clazz = (Class) fromStringTo(Class.class).execute(var.getClassName()); + Class clazz = toClass(var.getClassName()); VariableValueFactory valueFactory = new BeanFactoryVariableValueFactory(clazz, getFlow() .getApplicationContext().getAutowireCapableBeanFactory()); return new FlowVariable(var.getName(), valueFactory); @@ -499,7 +499,7 @@ public class FlowModelFlowBuilder extends AbstractFlowBuilder { private void parseAndSetMappingConversionExecutor(AbstractMappingModel mappingModel, DefaultMapping mapping) { if (StringUtils.hasText(mappingModel.getType())) { - Class type = (Class) fromStringTo(Class.class).execute(mappingModel.getType()); + Class type = toClass(mappingModel.getType()); ConversionExecutor typeConverter = new RuntimeBindingConversionExecutor(type, getLocalContext() .getConversionService()); mapping.setTypeConverter(typeConverter); @@ -624,7 +624,7 @@ public class FlowModelFlowBuilder extends AbstractFlowBuilder { } private ViewVariable parseViewVariable(VarModel var) { - Class clazz = (Class) fromStringTo(Class.class).execute(var.getClassName()); + Class clazz = toClass(var.getClassName()); VariableValueFactory valueFactory = new BeanFactoryVariableValueFactory(clazz, getFlow() .getApplicationContext().getAutowireCapableBeanFactory()); return new ViewVariable(var.getName(), valueFactory); @@ -718,7 +718,7 @@ public class FlowModelFlowBuilder extends AbstractFlowBuilder { private FlowExecutionExceptionHandler parseTransitionExecutingExceptionHandler(TransitionModel transition) { TransitionExecutingFlowExecutionExceptionHandler handler = new TransitionExecutingFlowExecutionExceptionHandler(); - Class exceptionClass = (Class) fromStringTo(Class.class).execute(transition.getOnException()); + Class exceptionClass = toClass(transition.getOnException()); TargetStateResolver targetStateResolver = (TargetStateResolver) fromStringTo(TargetStateResolver.class) .execute(transition.getTo()); handler.add(exceptionClass, targetStateResolver); @@ -820,7 +820,7 @@ public class FlowModelFlowBuilder extends AbstractFlowBuilder { new FluentParserContext().evaluate(RequestContext.class)); Class expectedResultType = null; if (StringUtils.hasText(evaluate.getResultType())) { - expectedResultType = (Class) fromStringTo(Class.class).execute(evaluate.getResultType()); + expectedResultType = toClass(evaluate.getResultType()); } return new ActionResultExposer(resultExpression, expectedResultType, getLocalContext() .getConversionService()); @@ -849,7 +849,7 @@ public class FlowModelFlowBuilder extends AbstractFlowBuilder { new FluentParserContext().evaluate(RequestContext.class)); Class expectedType = null; if (StringUtils.hasText(set.getType())) { - expectedType = (Class) fromStringTo(Class.class).execute(set.getType()); + expectedType = toClass(set.getType()); } return new SetAction(nameExpression, valueExpression, expectedType, getLocalContext().getConversionService()); } @@ -874,7 +874,7 @@ public class FlowModelFlowBuilder extends AbstractFlowBuilder { private Object parseAttributeValueIfNecessary(AttributeModel attribute, String stringValue) { if (StringUtils.hasText(attribute.getType())) { - Class targetClass = (Class) fromStringTo(Class.class).execute(attribute.getType()); + Class targetClass = toClass(attribute.getType()); return fromStringTo(targetClass).execute(stringValue); } else { return stringValue; @@ -909,6 +909,10 @@ public class FlowModelFlowBuilder extends AbstractFlowBuilder { return getLocalContext().getConversionService().getConversionExecutor(String.class, targetType); } + private Class toClass(String name) { + return getLocalContext().getConversionService().getClassByName(name); + } + private static class FlowRelativeResourceLoader implements ResourceLoader { private Resource resource; 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 9d860e13..0dc3d209 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 @@ -123,6 +123,11 @@ public class FlowBuilderContextImpl implements FlowBuilderContext { throws ConversionExecutionException { return getFlowBuilderServices().getConversionService().getConversionExecutor(sourceClass, targetClass); } + + public Class getClassByName(String name) { + return getFlowBuilderServices().getConversionService().getClassByName(name); + } + } } \ No newline at end of file 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 98bc9256..904bbb02 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 @@ -54,22 +54,12 @@ public class FlowBuilderServicesBeanDefinitionParserTests extends TestCase { public static class TestConversionService implements ConversionService { - public Class getClassByAlias(String alias) throws ConversionExecutionException { - throw new UnsupportedOperationException("Auto-generated method stub"); - } - public ConversionExecutor getConversionExecutor(Class sourceClass, Class targetClass) throws ConversionExecutionException { throw new UnsupportedOperationException("Auto-generated method stub"); } - public ConversionExecutor getConversionExecutorByTargetAlias(Class sourceClass, String targetAlias) - throws ConversionExecutionException { - throw new UnsupportedOperationException("Auto-generated method stub"); - } - - public ConversionExecutor[] getConversionExecutorsForSource(Class sourceClass) - throws ConversionExecutionException { + public Class getClassByName(String alias) throws ConversionExecutionException { throw new UnsupportedOperationException("Auto-generated method stub"); }