diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToClass.java b/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToClass.java index c8d89c74..006d22ec 100644 --- a/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToClass.java +++ b/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToClass.java @@ -24,12 +24,15 @@ import org.springframework.util.ClassUtils; */ public class StringToClass extends StringToObject { - public StringToClass() { + private ClassLoader classLoader; + + public StringToClass(ClassLoader classLoader) { super(Class.class); + this.classLoader = classLoader; } public Object toObject(String string, Class objectClass) throws Exception { - return ClassUtils.forName(string); + return ClassUtils.forName(string, classLoader); } public String toString(Object object) throws Exception { 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 73f7eddf..c07a54df 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,6 +20,7 @@ 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; @@ -36,6 +37,7 @@ 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 @@ -43,13 +45,15 @@ import org.springframework.core.enums.LabeledEnum; * * @author Keith Donald */ -public class DefaultConversionService extends GenericConversionService { +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(); + /** * Creates a new default conversion service, installing the default converters. */ @@ -72,7 +76,7 @@ public class DefaultConversionService extends GenericConversionService { addConverter(new StringToDouble()); addConverter(new StringToBigInteger()); addConverter(new StringToBigDecimal()); - addConverter(new StringToClass()); + addConverter(new StringToClass(classLoader)); addConverter(new StringToLocale()); addConverter(new StringToDate()); addConverter(new StringToLabeledEnum()); @@ -96,6 +100,10 @@ public class DefaultConversionService extends GenericConversionService { addAlias("labeledEnum", LabeledEnum.class); } + public void setBeanClassLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + } + /** * Returns the shared {@link DefaultConversionService} instance. */ 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 3a4de595..5407e290 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 @@ -19,6 +19,7 @@ import java.util.Iterator; import java.util.Set; import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.binding.convert.ConversionExecutor; @@ -27,6 +28,7 @@ import org.springframework.binding.convert.service.DefaultConversionService; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; import org.springframework.webflow.conversation.ConversationManager; import org.springframework.webflow.conversation.impl.SessionBindingConversationManager; import org.springframework.webflow.core.collection.AttributeMap; @@ -56,7 +58,7 @@ import org.springframework.webflow.mvc.builder.MvcEnvironment; * @author Keith Donald * @author Erwin Vervaet */ -class FlowExecutorFactoryBean implements FactoryBean, ApplicationContextAware, InitializingBean { +class FlowExecutorFactoryBean implements FactoryBean, ApplicationContextAware, BeanClassLoaderAware, InitializingBean { private static final String ALWAYS_REDIRECT_ON_PAUSE = "alwaysRedirectOnPause"; @@ -76,6 +78,8 @@ class FlowExecutorFactoryBean implements FactoryBean, ApplicationContextAware, I private MvcEnvironment environment; + private ClassLoader classLoader; + /** * Sets the flow definition locator that will locate flow definitions needed for execution. Typically also a * {@link FlowDefinitionRegistry}. Required. @@ -123,6 +127,12 @@ class FlowExecutorFactoryBean implements FactoryBean, ApplicationContextAware, I environment = MvcEnvironment.environmentFor(applicationContext); } + // implement BeanClassLoaderAware + + public void setBeanClassLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + } + // implementing InitializingBean public void afterPropertiesSet() throws Exception { @@ -219,6 +229,16 @@ class FlowExecutorFactoryBean implements FactoryBean, ApplicationContextAware, I } private Class fromStringToClass(String name) { - return conversionService.getClassForAlias(name); + Class clazz = conversionService.getClassForAlias(name); + if (clazz != null) { + return clazz; + } else { + try { + return ClassUtils.forName(name, classLoader); + } catch (ClassNotFoundException e) { + throw new IllegalArgumentException("Unable to load class '" + 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 b03f4fde..23ce3f3a 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 @@ -19,6 +19,7 @@ import java.io.IOException; import java.util.Iterator; import java.util.Set; +import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.binding.convert.ConversionExecutor; @@ -53,7 +54,7 @@ import org.springframework.webflow.engine.model.registry.FlowModelRegistryImpl; * @author Keith Donald * @author Jeremy Grelle */ -class FlowRegistryFactoryBean implements FactoryBean, InitializingBean { +class FlowRegistryFactoryBean implements FactoryBean, BeanClassLoaderAware, InitializingBean { private FlowLocation[] flowLocations; @@ -65,6 +66,8 @@ class FlowRegistryFactoryBean implements FactoryBean, InitializingBean { private FlowDefinitionRegistry parent; + private ClassLoader classLoader; + /** * The definition registry produced by this factory bean. */ @@ -117,6 +120,12 @@ class FlowRegistryFactoryBean implements FactoryBean, InitializingBean { this.parent = parent; } + // implement BeanClassLoaderAware + + public void setBeanClassLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + } + public void afterPropertiesSet() throws Exception { flowResourceFactory = new FlowDefinitionResourceFactory(flowBuilderServices.getApplicationContext()); flowRegistry = new FlowDefinitionRegistryImpl(); @@ -236,20 +245,33 @@ class FlowRegistryFactoryBean implements FactoryBean, InitializingBean { } } - private Class fromStringToClass(String type) { - return flowBuilderServices.getConversionService().getClassForAlias(type); + private Class fromStringToClass(String name) { + Class clazz = flowBuilderServices.getConversionService().getClassForAlias(name); + if (clazz != null) { + return clazz; + } else { + return loadClass(name); + } + } + + private Class loadClass(String name) { + try { + return ClassUtils.forName(name, classLoader); + } catch (ClassNotFoundException e) { + throw new IllegalArgumentException("Unable to load class '" + name + "'"); + } } private FlowDefinition buildFlowDefinition(FlowBuilderInfo builderInfo) { try { - Class flowBuilderClass = ClassUtils.forName(builderInfo.getClassName()); + Class flowBuilderClass = loadClass(builderInfo.getClassName()); FlowBuilder builder = (FlowBuilder) flowBuilderClass.newInstance(); AttributeMap flowAttributes = getFlowAttributes(builderInfo.getAttributes()); FlowBuilderContext builderContext = new FlowBuilderContextImpl(builderInfo.getId(), flowAttributes, flowRegistry, flowBuilderServices); FlowAssembler assembler = new FlowAssembler(builder, builderContext); return assembler.assembleFlow(); - } catch (ClassNotFoundException e) { + } catch (IllegalArgumentException e) { throw new FlowDefinitionConstructionException(builderInfo.getId(), e); } catch (InstantiationException e) { throw new FlowDefinitionConstructionException(builderInfo.getId(), e); 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 d8130b45..a9b4ecb6 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 @@ -43,6 +43,7 @@ import org.springframework.context.support.ReloadableResourceBundleMessageSource import org.springframework.core.JdkVersion; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; +import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.request.RequestScope; @@ -910,7 +911,17 @@ public class FlowModelFlowBuilder extends AbstractFlowBuilder { } private Class toClass(String name) { - return getLocalContext().getConversionService().getClassForAlias(name); + Class clazz = getLocalContext().getConversionService().getClassForAlias(name); + if (clazz != null) { + return clazz; + } else { + try { + ClassLoader classLoader = getLocalContext().getApplicationContext().getClassLoader(); + return ClassUtils.forName(name, classLoader); + } catch (ClassNotFoundException e) { + throw new IllegalArgumentException("Unable to load class '" + name + "'"); + } + } } private static class FlowRelativeResourceLoader implements ResourceLoader { diff --git a/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/BindingModel.java b/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/BindingModel.java index 957abaac..04c5299b 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/BindingModel.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/BindingModel.java @@ -66,7 +66,7 @@ public class BindingModel extends AbstractErrors { * @param objectName the name of the bound model object * @param boundObject the bound model object * @param expressionParser the expression parser used to access model object properties - * @param formatterRegistry the formatter registry used to access formatters for formatting properties + * @param conversionService the registry used to access converters for formatting properties * @param messageContext the message context containing flow messages to display */ public BindingModel(String objectName, Object boundObject, ExpressionParser expressionParser,