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 deleted file mode 100644 index 7b3a7e43..00000000 --- a/spring-binding/src/main/java/org/springframework/binding/expression/el/DefaultExpressionFactoryUtils.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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.el; - -import javax.el.ExpressionFactory; - -import org.springframework.util.ClassUtils; - -/** - * A helper for creating a new expression factory instance using the default expression factory class configured for the - * VM. - * - * @author Keith Donald - */ -public class DefaultExpressionFactoryUtils { - - // TODO - change default to Spring EL when it becomes available - private static final String DEFAULT_EXPRESSION_FACTORY = "org.jboss.el.ExpressionFactoryImpl"; - - /** - * Returns the type of ExpressionFactory configured for this VM. - */ - public static String getDefaultExpressionFactoryClassName() { - return DEFAULT_EXPRESSION_FACTORY; - } - - /** - * Creates a new instance of the expression factory configured for this VM. - * @throws IllegalStateException if the ExpressionFactory class cannot be instantiated - */ - public static ExpressionFactory createExpressionFactory() throws IllegalStateException { - Class expressionFactoryClass; - try { - expressionFactoryClass = ClassUtils.forName(getDefaultExpressionFactoryClassName(), - DefaultExpressionFactoryUtils.class.getClassLoader()); - } catch (ClassNotFoundException e) { - IllegalStateException ise = new IllegalStateException( - "The default ExpressionFactory class '" - + getDefaultExpressionFactoryClassName() - + "' could not be found in the classpath. " - + "Please add this to your classpath or set the default ExpressionFactory class name to something that is in the classpath."); - ise.initCause(e); - throw ise; - } catch (NoClassDefFoundError e) { - IllegalStateException ise = new IllegalStateException( - "The default ExpressionFactory class '" - + getDefaultExpressionFactoryClassName() - + "' could not be found in the classpath. " - + "Please add this to your classpath or set the default ExpressionFactory class name to something that is in the classpath."); - ise.initCause(e); - throw ise; - } - try { - return (ExpressionFactory) expressionFactoryClass.newInstance(); - } catch (Exception e) { - IllegalStateException ise = new IllegalStateException("An instance of the default ExpressionFactory '" - + getDefaultExpressionFactoryClassName() - + "' could not be instantiated. Check your EL implementation configuration."); - ise.initCause(e); - throw ise; - } - } -} \ No newline at end of file diff --git a/spring-binding/src/main/java/org/springframework/binding/expression/spel/SpringELExpression.java b/spring-binding/src/main/java/org/springframework/binding/expression/spel/SpringELExpression.java index 3ff96b0a..4543b56a 100644 --- a/spring-binding/src/main/java/org/springframework/binding/expression/spel/SpringELExpression.java +++ b/spring-binding/src/main/java/org/springframework/binding/expression/spel/SpringELExpression.java @@ -22,6 +22,7 @@ import java.util.Map; import org.springframework.binding.expression.EvaluationException; import org.springframework.binding.expression.Expression; +import org.springframework.binding.expression.PropertyNotFoundException; import org.springframework.binding.expression.ValueCoercionException; import org.springframework.expression.spel.SpelEvaluationException; import org.springframework.expression.spel.SpelMessage; @@ -76,6 +77,9 @@ public class SpringELExpression implements Expression { updateEvaluationContext(rootObject); return expression.getValue(evaluationContext, expectedType); } catch (SpelEvaluationException e) { + if (e.getMessageCode().equals(SpelMessage.PROPERTY_OR_FIELD_NOT_READABLE)) { + throw new PropertyNotFoundException(rootObject.getClass(), getExpressionString(), e); + } if (e.getMessageCode().equals(SpelMessage.TYPE_CONVERSION_ERROR)) { throw new ValueCoercionException(rootObject.getClass(), getExpressionString(), null, expectedType, e); } @@ -86,8 +90,17 @@ public class SpringELExpression implements Expression { } public Class getValueType(Object rootObject) throws EvaluationException { - evaluationContext.setRootObject(rootObject); - return expression.getValueType(evaluationContext); + try { + evaluationContext.setRootObject(rootObject); + return expression.getValueType(evaluationContext); + } catch (SpelEvaluationException e) { + if (e.getMessageCode().equals(SpelMessage.PROPERTY_OR_FIELD_NOT_READABLE)) { + throw new PropertyNotFoundException(rootObject.getClass(), getExpressionString(), e); + } + throw new EvaluationException(rootObject.getClass(), getExpressionString(), + "An ELException occurred getting the value type for expression '" + getExpressionString() + + "' on context [" + rootObject.getClass() + "]", e); + } } public void setValue(Object rootObject, Object value) throws EvaluationException { @@ -95,6 +108,9 @@ public class SpringELExpression implements Expression { updateEvaluationContext(rootObject); expression.setValue(evaluationContext, value); } catch (SpelEvaluationException e) { + if (e.getMessageCode().equals(SpelMessage.PROPERTY_OR_FIELD_NOT_WRITABLE)) { + throw new PropertyNotFoundException(rootObject.getClass(), getExpressionString(), e); + } if (e.getMessageCode().equals(SpelMessage.EXCEPTION_DURING_PROPERTY_WRITE)) { throw new ValueCoercionException(rootObject.getClass(), getExpressionString(), value, expectedType, e); } diff --git a/spring-binding/src/main/java/org/springframework/binding/expression/spel/SpringELExpressionParser.java b/spring-binding/src/main/java/org/springframework/binding/expression/spel/SpringELExpressionParser.java index f353aa0b..a02d5080 100644 --- a/spring-binding/src/main/java/org/springframework/binding/expression/spel/SpringELExpressionParser.java +++ b/spring-binding/src/main/java/org/springframework/binding/expression/spel/SpringELExpressionParser.java @@ -16,6 +16,7 @@ package org.springframework.binding.expression.spel; import java.util.ArrayList; +import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -26,6 +27,7 @@ import org.springframework.binding.expression.ExpressionVariable; import org.springframework.binding.expression.ParserContext; import org.springframework.binding.expression.ParserException; import org.springframework.binding.expression.support.NullParserContext; +import org.springframework.context.expression.MapAccessor; import org.springframework.core.convert.ConversionService; import org.springframework.expression.EvaluationContext; import org.springframework.expression.PropertyAccessor; @@ -33,6 +35,9 @@ import org.springframework.expression.TypeConverter; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.expression.spel.support.StandardTypeConverter; +import org.springframework.format.FormatterRegistry; +import org.springframework.format.datetime.DateFormatter; +import org.springframework.format.support.FormattingConversionServiceFactoryBean; import org.springframework.util.Assert; /** @@ -47,16 +52,34 @@ public class SpringELExpressionParser implements ExpressionParser { private SpelExpressionParser expressionParser; - private TypeConverter typeConverter = new StandardTypeConverter(); + private ConversionService conversionService; private List propertyAccessors = new ArrayList(); public SpringELExpressionParser(SpelExpressionParser expressionParser) { this.expressionParser = expressionParser; + this.propertyAccessors.add(new MapAccessor()); + } + + public ConversionService getConversionService() { + ensureConversionServiceInitialized(); + return conversionService; } public void setConversionService(ConversionService conversionService) { - typeConverter = new StandardTypeConverter(conversionService); + this.conversionService = conversionService; + } + + private void ensureConversionServiceInitialized() { + if (this.conversionService == null) { + FormattingConversionServiceFactoryBean factoryBean = new FormattingConversionServiceFactoryBean() { + protected void installFormatters(FormatterRegistry registry) { + registry.addFormatterForFieldType(Date.class, new DateFormatter()); + } + }; + factoryBean.afterPropertiesSet(); + this.conversionService = factoryBean.getObject(); + } } public void addPropertyAccessor(PropertyAccessor propertyAccessor) { @@ -67,13 +90,17 @@ public class SpringELExpressionParser implements ExpressionParser { Assert.hasText(expressionString, "The expression string to parse is required and must not be empty"); parserContext = (parserContext == null) ? NullParserContext.INSTANCE : parserContext; StandardEvaluationContext evaluationContext = new StandardEvaluationContext(); - evaluationContext.setTypeConverter(typeConverter); + evaluationContext.setTypeConverter(getTypeConverter()); evaluationContext.getPropertyAccessors().addAll(propertyAccessors); Map spelExpressionVariables = parseSpelExpressionVariables(parserContext.getExpressionVariables()); return new SpringELExpression(parseSpelExpression(expressionString, parserContext), spelExpressionVariables, parserContext.getExpectedEvaluationResultType(), evaluationContext); } + private TypeConverter getTypeConverter() { + return (conversionService != null) ? new StandardTypeConverter(conversionService) : new StandardTypeConverter(); + } + private org.springframework.expression.Expression parseSpelExpression(String expression, ParserContext parserContext) { return expressionParser.parseExpression(expression, getSpelParserContext(parserContext)); } diff --git a/spring-binding/src/test/java/org/springframework/binding/expression/spel/ELExpressionParserCompatibilityTests.java b/spring-binding/src/test/java/org/springframework/binding/expression/spel/ELExpressionParserCompatibilityTests.java index 61b452cc..d29b8ea4 100644 --- a/spring-binding/src/test/java/org/springframework/binding/expression/spel/ELExpressionParserCompatibilityTests.java +++ b/spring-binding/src/test/java/org/springframework/binding/expression/spel/ELExpressionParserCompatibilityTests.java @@ -101,7 +101,7 @@ public class ELExpressionParserCompatibilityTests extends TestCase { public void testParseEvalExpressionWithContextCustomELVariableResolver() { String expressionString = "specialProperty"; Expression exp = parser.parseExpression(expressionString, new FluentParserContext().evaluate(TestBean.class)); - assertEquals("Custom resolver resolved this special property!", exp.getValue(new TestBean())); + assertEquals("Custom resolver resolved this special property!", exp.getValue(null)); } public void testParseBeanEvalExpressionInvalidELVariable() { diff --git a/spring-binding/src/test/java/org/springframework/binding/mapping/DefaultMapperTests.java b/spring-binding/src/test/java/org/springframework/binding/mapping/DefaultMapperTests.java index 5c3b439f..163539bb 100644 --- a/spring-binding/src/test/java/org/springframework/binding/mapping/DefaultMapperTests.java +++ b/spring-binding/src/test/java/org/springframework/binding/mapping/DefaultMapperTests.java @@ -7,14 +7,14 @@ import java.util.Map; import junit.framework.TestCase; import org.springframework.binding.expression.ExpressionParser; -import org.springframework.binding.expression.el.DefaultExpressionFactoryUtils; -import org.springframework.binding.expression.el.ELExpressionParser; +import org.springframework.binding.expression.spel.SpringELExpressionParser; import org.springframework.binding.mapping.impl.DefaultMapper; import org.springframework.binding.mapping.impl.DefaultMapping; +import org.springframework.expression.spel.standard.SpelExpressionParser; public class DefaultMapperTests extends TestCase { private DefaultMapper mapper = new DefaultMapper(); - private ExpressionParser parser = new ELExpressionParser(DefaultExpressionFactoryUtils.createExpressionFactory()); + private ExpressionParser parser = new SpringELExpressionParser(new SpelExpressionParser()); public void testMapping() { DefaultMapping mapping1 = new DefaultMapping(parser.parseExpression("foo", null), parser.parseExpression("bar", diff --git a/spring-faces/.classpath b/spring-faces/.classpath index 559467fa..3e1988ee 100644 --- a/spring-faces/.classpath +++ b/spring-faces/.classpath @@ -26,6 +26,7 @@ + diff --git a/spring-faces/ivy.xml b/spring-faces/ivy.xml index 43f540f7..d78698cc 100644 --- a/spring-faces/ivy.xml +++ b/spring-faces/ivy.xml @@ -30,6 +30,7 @@ + diff --git a/spring-faces/pom.xml b/spring-faces/pom.xml index f85e0042..f05f7492 100644 --- a/spring-faces/pom.xml +++ b/spring-faces/pom.xml @@ -27,6 +27,11 @@ spring-core ${spring.version} + + org.springframework + spring-expression + ${spring.version} + org.springframework spring-web diff --git a/spring-faces/src/main/java/org/springframework/faces/config/FacesFlowBuilderServicesBeanDefinitionParser.java b/spring-faces/src/main/java/org/springframework/faces/config/FacesFlowBuilderServicesBeanDefinitionParser.java index 25b7dd6f..91ec1e94 100644 --- a/spring-faces/src/main/java/org/springframework/faces/config/FacesFlowBuilderServicesBeanDefinitionParser.java +++ b/spring-faces/src/main/java/org/springframework/faces/config/FacesFlowBuilderServicesBeanDefinitionParser.java @@ -16,7 +16,6 @@ package org.springframework.faces.config; import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.beans.factory.parsing.BeanComponentDefinition; import org.springframework.beans.factory.parsing.CompositeComponentDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; @@ -36,12 +35,11 @@ public class FacesFlowBuilderServicesBeanDefinitionParser extends AbstractSingle BeanDefinitionParser { // --------------------------- Full qualified class names ----------------------- // - private static final String DEFAULT_EXPRESSION_FACTORY_UTILS_CLASS_NAME = "org.springframework.binding.expression.el.DefaultExpressionFactoryUtils"; private static final String FACES_CONVERSION_SERVICE_CLASS_NAME = "org.springframework.faces.model.converter.FacesConversionService"; private static final String FLOW_BUILDER_SERVICES_CLASS_NAME = "org.springframework.webflow.engine.builder.support.FlowBuilderServices"; private static final String JSF_VIEW_FACTORY_CREATOR_CLASS_NAME = "org.springframework.faces.webflow.JsfViewFactoryCreator"; - private static final String JSF_MANAGED_BEAN_AWARE_E_L_EXPRESSION_PARSER_CLASS_NAME = "org.springframework.faces.webflow.JsfManagedBeanAwareELExpressionParser"; - private static final String WEBFLOW_EL_EXPRESSION_PARSER_CLASS_NAME = "org.springframework.webflow.expression.el.WebFlowELExpressionParser"; + private static final String FACES_SPRING_EL_EXPRESSION_PARSER_CLASS_NAME = "org.springframework.faces.webflow.FacesSpringELExpressionParser"; + private static final String WEBFLOW_SPRING_EL_EXPRESSION_PARSER_CLASS_NAME = "org.springframework.webflow.expression.spel.WebFlowSpringELExpressionParser"; // --------------------------- XML Config Attributes ----------------------- // private static final String CONVERSION_SERVICE_ATTR = "conversion-service"; @@ -106,27 +104,25 @@ public class FacesFlowBuilderServicesBeanDefinitionParser extends AbstractSingle private void parseExpressionParser(Element element, ParserContext context, BeanDefinitionBuilder definitionBuilder, boolean enableManagedBeans) { - String conversionService = getConversionService(definitionBuilder); + // String conversionService = getConversionService(definitionBuilder); String expressionParser = element.getAttribute(EXPRESSION_PARSER_ATTR); if (!StringUtils.hasText(expressionParser)) { - BeanDefinitionBuilder expressionFactoryBuilder = BeanDefinitionBuilder - .genericBeanDefinition(DEFAULT_EXPRESSION_FACTORY_UTILS_CLASS_NAME); - expressionFactoryBuilder.setFactoryMethod("createExpressionFactory"); + BeanDefinitionBuilder spelExpressionParser = BeanDefinitionBuilder + .genericBeanDefinition("org.springframework.expression.spel.standard.SpelExpressionParser"); BeanDefinitionBuilder expressionParserBuilder; if (enableManagedBeans) { expressionParserBuilder = BeanDefinitionBuilder - .genericBeanDefinition(JSF_MANAGED_BEAN_AWARE_E_L_EXPRESSION_PARSER_CLASS_NAME); + .genericBeanDefinition(FACES_SPRING_EL_EXPRESSION_PARSER_CLASS_NAME); } else { expressionParserBuilder = BeanDefinitionBuilder - .genericBeanDefinition(WEBFLOW_EL_EXPRESSION_PARSER_CLASS_NAME); + .genericBeanDefinition(WEBFLOW_SPRING_EL_EXPRESSION_PARSER_CLASS_NAME); } - expressionParserBuilder.addConstructorArgValue(expressionFactoryBuilder.getBeanDefinition()); - expressionParserBuilder.addPropertyReference(CONVERSION_SERVICE_PROPERTY, conversionService); + expressionParserBuilder.addConstructorArgValue(spelExpressionParser.getBeanDefinition()); expressionParser = registerInfrastructureComponent(element, context, expressionParserBuilder); } else if (enableManagedBeans) { @@ -145,19 +141,12 @@ public class FacesFlowBuilderServicesBeanDefinitionParser extends AbstractSingle } } - private String getConversionService(BeanDefinitionBuilder definitionBuilder) { - RuntimeBeanReference conversionServiceReference = (RuntimeBeanReference) definitionBuilder.getBeanDefinition() - .getPropertyValues().getPropertyValue(CONVERSION_SERVICE_PROPERTY).getValue(); - return conversionServiceReference.getBeanName(); - } - private String registerInfrastructureComponent(Element element, ParserContext context, BeanDefinitionBuilder componentBuilder) { String beanName = context.getReaderContext().generateBeanName(componentBuilder.getRawBeanDefinition()); componentBuilder.getRawBeanDefinition().setSource(context.extractSource(element)); componentBuilder.getRawBeanDefinition().setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - context.registerBeanComponent(new BeanComponentDefinition(componentBuilder.getBeanDefinition(), - beanName)); + context.registerBeanComponent(new BeanComponentDefinition(componentBuilder.getBeanDefinition(), beanName)); return beanName; } } \ No newline at end of file diff --git a/spring-faces/src/main/java/org/springframework/faces/webflow/FacesSpringELExpressionParser.java b/spring-faces/src/main/java/org/springframework/faces/webflow/FacesSpringELExpressionParser.java new file mode 100644 index 00000000..6faeef3a --- /dev/null +++ b/spring-faces/src/main/java/org/springframework/faces/webflow/FacesSpringELExpressionParser.java @@ -0,0 +1,37 @@ +/* + * Copyright 2004-2010 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.faces.webflow; + +import org.springframework.binding.expression.ExpressionParser; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.webflow.expression.spel.WebFlowSpringELExpressionParser; + +/** + *

+ * A Spring EL {@link ExpressionParser} for use with JSF. Adds JSF specific Spring EL PropertyAccessors. + *

+ * + * @author Rossen Stoyanchev + * @since 2.1 + */ +public class FacesSpringELExpressionParser extends WebFlowSpringELExpressionParser { + + public FacesSpringELExpressionParser(SpelExpressionParser expressionParser) { + super(expressionParser); + addPropertyAccessor(new JsfManagedBeanPropertyAccessor()); + } + +} diff --git a/spring-faces/src/main/java/org/springframework/faces/webflow/JsfManagedBeanPropertyAccessor.java b/spring-faces/src/main/java/org/springframework/faces/webflow/JsfManagedBeanPropertyAccessor.java new file mode 100644 index 00000000..4843324f --- /dev/null +++ b/spring-faces/src/main/java/org/springframework/faces/webflow/JsfManagedBeanPropertyAccessor.java @@ -0,0 +1,111 @@ +/* + * Copyright 2004-2010 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.faces.webflow; + +import javax.el.ELContext; +import javax.el.ExpressionFactory; +import javax.el.ValueExpression; +import javax.faces.context.FacesContext; + +import org.springframework.expression.AccessException; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.PropertyAccessor; +import org.springframework.expression.TypedValue; +import org.springframework.util.Assert; +import org.springframework.webflow.context.ExternalContext; +import org.springframework.webflow.core.collection.MutableAttributeMap; +import org.springframework.webflow.execution.RequestContext; +import org.springframework.webflow.execution.RequestContextHolder; + +/** + *

+ * Spring EL PropertyAccessor that checks request, session, and application scopes for existing JSF-managed beans. This + * allows traditional JSF-managed beans (defined in faces-config.xml) to be resolved through expressions in a flow + * definition. + *

+ *

+ * The preferred approach is to instead use Spring to configure such beans, but this is meant to ease migration for + * users with existing JSF artifacts. This resolver will delegate to a temporary FacesContext so that JSF managed bean + * initialization will be triggered if the bean has not already been initialized by JSF. + *

+ *

+ * Source code adapted from {@link JsfManagedBeanResolver}. + *

+ * + * @author Jeremy Grelle + * @author Rossen Stoyanchev + * + * @since 2.1 + */ +public class JsfManagedBeanPropertyAccessor implements PropertyAccessor { + + public Class[] getSpecificTargetClasses() { + return null; + } + + public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException { + return (getJsfManagedBean(name) != null); + } + + public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException { + return new TypedValue(getJsfManagedBean(name)); + } + + public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException { + return (getScopeForBean(name) != null); + } + + public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException { + MutableAttributeMap map = getScopeForBean(name); + if (map != null) { + map.put(name, newValue); + } + } + + /** + * Locates a JSF managed bean through a temporary FacesContext. This method is only meant to be called from the Flow + * Execution. It assumes the FacesContext will not be available and creates a temporary one on the fly. + * + * @param name The name of the bean to resolve. + * @return The JSF Managed Bean instance if found. + */ + private Object getJsfManagedBean(String name) { + RequestContext requestContext = RequestContextHolder.getRequestContext(); + Assert.notNull(requestContext, "RequestContext cannot be null. " + + "This PropertyAccessor is only intended to be invoked from an active Flow Execution."); + FacesContext facesContext = FlowFacesContext.newInstance(requestContext, FlowLifecycle.newInstance()); + try { + ExpressionFactory factory = facesContext.getApplication().getExpressionFactory(); + ELContext elContext = facesContext.getELContext(); + ValueExpression expression = factory.createValueExpression(elContext, "#{" + name + "}", Object.class); + return expression.getValue(facesContext.getELContext()); + } finally { + facesContext.release(); + } + } + + private MutableAttributeMap getScopeForBean(String name) { + ExternalContext externalContext = RequestContextHolder.getRequestContext().getExternalContext(); + if (externalContext.getRequestMap().contains(name)) { + return externalContext.getRequestMap(); + } else if (externalContext.getSessionMap().contains(name)) { + return externalContext.getSessionMap(); + } else if (externalContext.getApplicationMap().contains(name)) { + return externalContext.getApplicationMap(); + } + return null; + } +} 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 93f3c250..b47d33be 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 @@ -11,16 +11,17 @@ import org.springframework.binding.convert.ConversionExecutorNotFoundException; import org.springframework.binding.convert.ConversionService; import org.springframework.binding.expression.Expression; import org.springframework.binding.expression.ExpressionParser; +import org.springframework.binding.expression.spel.SpringELExpressionParser; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.faces.model.converter.FacesConversionService; +import org.springframework.faces.webflow.FacesSpringELExpressionParser; import org.springframework.faces.webflow.JSFMockHelper; -import org.springframework.faces.webflow.JsfManagedBeanAwareELExpressionParser; import org.springframework.faces.webflow.JsfViewFactoryCreator; import org.springframework.webflow.engine.builder.BinderConfiguration; import org.springframework.webflow.engine.builder.ViewFactoryCreator; import org.springframework.webflow.engine.builder.support.FlowBuilderServices; import org.springframework.webflow.execution.ViewFactory; -import org.springframework.webflow.expression.el.WebFlowELExpressionParser; +import org.springframework.webflow.expression.spel.WebFlowSpringELExpressionParser; public class FacesFlowBuilderServicesBeanDefinitionParserTests extends TestCase { @@ -40,7 +41,7 @@ public class FacesFlowBuilderServicesBeanDefinitionParserTests extends TestCase public void testConfigureDefaults() { builderServices = (FlowBuilderServices) context.getBean("flowBuilderServicesDefault"); assertNotNull(builderServices); - assertTrue(builderServices.getExpressionParser() instanceof WebFlowELExpressionParser); + assertTrue(builderServices.getExpressionParser() instanceof SpringELExpressionParser); assertTrue(builderServices.getViewFactoryCreator() instanceof JsfViewFactoryCreator); assertTrue(builderServices.getConversionService() instanceof FacesConversionService); assertFalse(builderServices.getDevelopment()); @@ -49,7 +50,7 @@ public class FacesFlowBuilderServicesBeanDefinitionParserTests extends TestCase public void testEnableManagedBeans() { builderServices = (FlowBuilderServices) context.getBean("flowBuilderServicesLegacy"); assertNotNull(builderServices); - assertTrue(builderServices.getExpressionParser() instanceof JsfManagedBeanAwareELExpressionParser); + assertTrue(builderServices.getExpressionParser() instanceof FacesSpringELExpressionParser); assertTrue(builderServices.getViewFactoryCreator() instanceof JsfViewFactoryCreator); assertTrue(builderServices.getConversionService() instanceof FacesConversionService); assertFalse(builderServices.getDevelopment()); @@ -58,7 +59,7 @@ public class FacesFlowBuilderServicesBeanDefinitionParserTests extends TestCase public void testFlowBuilderServicesAllCustomized() { builderServices = (FlowBuilderServices) context.getBean("flowBuilderServicesAllCustom"); assertNotNull(builderServices); - assertTrue(builderServices.getExpressionParser() instanceof WebFlowELExpressionParser); + assertTrue(builderServices.getExpressionParser() instanceof WebFlowSpringELExpressionParser); assertTrue(builderServices.getViewFactoryCreator() instanceof TestViewFactoryCreator); assertTrue(builderServices.getConversionService() instanceof TestConversionService); assertTrue(builderServices.getDevelopment()); @@ -68,8 +69,8 @@ public class FacesFlowBuilderServicesBeanDefinitionParserTests extends TestCase builderServices = (FlowBuilderServices) context.getBean("flowBuilderServicesConversionServiceCustom"); assertNotNull(builderServices); assertTrue(builderServices.getConversionService() instanceof TestConversionService); - assertTrue(builderServices.getExpressionParser() instanceof WebFlowELExpressionParser); - assertTrue(((WebFlowELExpressionParser) builderServices.getExpressionParser()).getConversionService() instanceof TestConversionService); + assertTrue(builderServices.getExpressionParser() instanceof WebFlowSpringELExpressionParser); + assertNotNull(((SpringELExpressionParser) builderServices.getExpressionParser()).getConversionService()); assertTrue(builderServices.getViewFactoryCreator() instanceof JsfViewFactoryCreator); assertFalse(builderServices.getDevelopment()); } diff --git a/spring-faces/src/test/java/org/springframework/faces/config/flow-builder-services.xml b/spring-faces/src/test/java/org/springframework/faces/config/flow-builder-services.xml index 53c22281..9b556c63 100644 --- a/spring-faces/src/test/java/org/springframework/faces/config/flow-builder-services.xml +++ b/spring-faces/src/test/java/org/springframework/faces/config/flow-builder-services.xml @@ -20,7 +20,11 @@ - + + + + + diff --git a/spring-faces/src/test/java/org/springframework/faces/webflow/JsfManagedBeanPropertyAccessorTests.java b/spring-faces/src/test/java/org/springframework/faces/webflow/JsfManagedBeanPropertyAccessorTests.java new file mode 100644 index 00000000..2af12a81 --- /dev/null +++ b/spring-faces/src/test/java/org/springframework/faces/webflow/JsfManagedBeanPropertyAccessorTests.java @@ -0,0 +1,86 @@ +/* + * Copyright 2004-2010 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.faces.webflow; + +import junit.framework.TestCase; + +import org.springframework.webflow.core.collection.MutableAttributeMap; +import org.springframework.webflow.execution.RequestContextHolder; +import org.springframework.webflow.test.MockRequestContext; + +public class JsfManagedBeanPropertyAccessorTests extends TestCase { + + JSFMockHelper jsfMock = new JSFMockHelper(); + + JsfManagedBeanPropertyAccessor accessor = new JsfManagedBeanPropertyAccessor(); + + private MockRequestContext requestContext; + + protected void setUp() throws Exception { + jsfMock.setUp(); + requestContext = new MockRequestContext(); + RequestContextHolder.setRequestContext(requestContext); + } + + protected void tearDown() throws Exception { + jsfMock.tearDown(); + } + + public void testCanRead() throws Exception { + jsfMock.externalContext().getRequestMap().put("myJsfBean", new Object()); + assertTrue(accessor.canRead(null, null, "myJsfBean")); + } + + public void testRead() throws Exception { + Object jsfBean = new Object(); + jsfMock.externalContext().getRequestMap().put("myJsfBean", jsfBean); + assertEquals(jsfBean, accessor.read(null, null, "myJsfBean").getValue()); + } + + public void testCanWrite() throws Exception { + assertFalse(accessor.canWrite(null, null, "myJsfBean")); + + MutableAttributeMap map = requestContext.getExternalContext().getRequestMap(); + map.put("myJsfBean", new Object()); + assertTrue(accessor.canWrite(null, null, "myJsfBean")); + map.clear(); + + map = requestContext.getExternalContext().getSessionMap(); + map.put("myJsfBean", new Object()); + assertTrue(accessor.canWrite(null, null, "myJsfBean")); + map.clear(); + + map = requestContext.getExternalContext().getApplicationMap(); + map.put("myJsfBean", new Object()); + assertTrue(accessor.canWrite(null, null, "myJsfBean")); + map.clear(); + } + + public void testWrite() throws Exception { + Object jsfBean1 = new Object(); + Object jsfBean2 = new Object(); + + MutableAttributeMap map = requestContext.getExternalContext().getRequestMap(); + accessor.write(null, null, "myJsfBean", jsfBean1); + assertNull("Write occurs only if bean is present in the map", map.get("myJsfBean")); + + map.put("myJsfBean", jsfBean1); + accessor.write(null, null, "myJsfBean", jsfBean2); + assertEquals(jsfBean2, map.get("myJsfBean")); + map.clear(); + } + +} diff --git a/spring-webflow-samples/booking-faces/src/main/webapp/WEB-INF/flows/main/main-flow.xml b/spring-webflow-samples/booking-faces/src/main/webapp/WEB-INF/flows/main/main-flow.xml index 8c71fe61..e0fa334e 100755 --- a/spring-webflow-samples/booking-faces/src/main/webapp/WEB-INF/flows/main/main-flow.xml +++ b/spring-webflow-samples/booking-faces/src/main/webapp/WEB-INF/flows/main/main-flow.xml @@ -7,7 +7,7 @@ - + diff --git a/spring-webflow-samples/booking-mvc/src/main/webapp/WEB-INF/login.jsp b/spring-webflow-samples/booking-mvc/src/main/webapp/WEB-INF/login.jsp index 7c888380..57a45ad6 100755 --- a/spring-webflow-samples/booking-mvc/src/main/webapp/WEB-INF/login.jsp +++ b/spring-webflow-samples/booking-mvc/src/main/webapp/WEB-INF/login.jsp @@ -1,9 +1,9 @@ <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> -<%@ page import="org.springframework.security.ui.AbstractProcessingFilter" %> -<%@ page import="org.springframework.security.ui.webapp.AuthenticationProcessingFilter" %> -<%@ page import="org.springframework.security.AuthenticationException" %> +<%@ page import="org.springframework.security.web.authentication.AbstractProcessingFilter" %> +<%@ page import="org.springframework.security.web.authentication.AuthenticationProcessingFilter" %> +<%@ page import="org.springframework.security.core.AuthenticationException" %>

Login Required

diff --git a/spring-webflow/.classpath b/spring-webflow/.classpath index 75ba73a4..f4dab87b 100644 --- a/spring-webflow/.classpath +++ b/spring-webflow/.classpath @@ -32,12 +32,13 @@ - + + diff --git a/spring-webflow/ivy.xml b/spring-webflow/ivy.xml index 12a959fa..b5df4b8e 100644 --- a/spring-webflow/ivy.xml +++ b/spring-webflow/ivy.xml @@ -33,6 +33,7 @@ + diff --git a/spring-webflow/pom.xml b/spring-webflow/pom.xml index 4c8954df..3aa12857 100644 --- a/spring-webflow/pom.xml +++ b/spring-webflow/pom.xml @@ -27,6 +27,11 @@ spring-core ${spring.version} + + org.springframework + spring-expression + ${spring.version} + org.springframework spring-web 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 13aea516..a79eb8ed 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 @@ -16,7 +16,6 @@ package org.springframework.webflow.config; import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.beans.factory.parsing.BeanComponentDefinition; import org.springframework.beans.factory.parsing.CompositeComponentDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; @@ -34,7 +33,8 @@ import org.w3c.dom.Element; class FlowBuilderServicesBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { // --------------------------- Full qualified class names ----------------------- // - private static final String DEFAULT_EXPRESSION_PARSER_FACTORY_CLASS_NAME = "org.springframework.webflow.expression.DefaultExpressionParserFactory"; + private static final String WEB_FLOW_SPRING_EL_EXPRESSION_PARSER_CLASS_NAME = "org.springframework.webflow.expression.spel.WebFlowSpringELExpressionParser"; + private static final String SPRING_EL_EXPRESSION_PARSER_CLASS_NAME = "org.springframework.expression.spel.standard.SpelExpressionParser"; private static final String DEFAULT_CONVERSION_SERVICE_CLASS_NAME = "org.springframework.binding.convert.service.DefaultConversionService"; private static final String FLOW_BUILDER_SERVICES_CLASS_NAME = "org.springframework.webflow.engine.builder.support.FlowBuilderServices"; private static final String MVC_VIEW_FACTORY_CREATOR_CLASS_NAME = "org.springframework.webflow.mvc.builder.MvcViewFactoryCreator"; @@ -82,12 +82,13 @@ class FlowBuilderServicesBeanDefinitionParser extends AbstractSingleBeanDefiniti private void parseExpressionParser(Element element, ParserContext context, BeanDefinitionBuilder definitionBuilder) { String expressionParser = element.getAttribute(EXPRESSION_PARSER_ATTR); if (!StringUtils.hasText(expressionParser)) { - String conversionService = getConversionService(definitionBuilder); - BeanDefinitionBuilder expressionParserBuilder = BeanDefinitionBuilder - .genericBeanDefinition(DEFAULT_EXPRESSION_PARSER_FACTORY_CLASS_NAME); - expressionParserBuilder.setFactoryMethod("getExpressionParser"); - expressionParserBuilder.addConstructorArgReference(conversionService); - expressionParser = registerInfrastructureComponent(element, context, expressionParserBuilder); + BeanDefinitionBuilder springElExpressionParserBuilder = BeanDefinitionBuilder + .genericBeanDefinition(SPRING_EL_EXPRESSION_PARSER_CLASS_NAME); + BeanDefinitionBuilder webFlowElExpressionParserBuilder = BeanDefinitionBuilder + .genericBeanDefinition(WEB_FLOW_SPRING_EL_EXPRESSION_PARSER_CLASS_NAME); + webFlowElExpressionParserBuilder + .addConstructorArgValue(springElExpressionParserBuilder.getBeanDefinition()); + expressionParser = registerInfrastructureComponent(element, context, webFlowElExpressionParserBuilder); } definitionBuilder.addPropertyReference(EXPRESSION_PARSER_PROPERTY, expressionParser); } @@ -109,19 +110,12 @@ class FlowBuilderServicesBeanDefinitionParser extends AbstractSingleBeanDefiniti } } - private String getConversionService(BeanDefinitionBuilder definitionBuilder) { - RuntimeBeanReference conversionServiceReference = (RuntimeBeanReference) definitionBuilder.getBeanDefinition() - .getPropertyValues().getPropertyValue(CONVERSION_SERVICE_PROPERTY).getValue(); - return conversionServiceReference.getBeanName(); - } - private String registerInfrastructureComponent(Element element, ParserContext context, BeanDefinitionBuilder componentBuilder) { String beanName = context.getReaderContext().generateBeanName(componentBuilder.getRawBeanDefinition()); componentBuilder.getRawBeanDefinition().setSource(context.extractSource(element)); componentBuilder.getRawBeanDefinition().setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - context.registerBeanComponent(new BeanComponentDefinition(componentBuilder.getBeanDefinition(), - beanName)); + context.registerBeanComponent(new BeanComponentDefinition(componentBuilder.getBeanDefinition(), beanName)); return beanName; } } \ No newline at end of file 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 daacacf8..08936215 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 @@ -43,7 +43,8 @@ class FlowRegistryBeanDefinitionParser extends AbstractSingleBeanDefinitionParse // --------------------------- Full qualified class names ----------------------- // private static final String DEFAULT_CONVERSION_SERVICE_CLASS_NAME = "org.springframework.binding.convert.service.DefaultConversionService"; - private static final String DEFAULT_EXPRESSION_PARSER_FACTORY_CLASS_NAME = "org.springframework.webflow.expression.DefaultExpressionParserFactory"; + private static final String WEB_FLOW_SPRING_EL_EXPRESSION_PARSER_CLASS_NAME = "org.springframework.webflow.expression.spel.WebFlowSpringELExpressionParser"; + private static final String SPRING_EL_EXPRESSION_PARSER_CLASS_NAME = "org.springframework.expression.spel.standard.SpelExpressionParser"; private static final String FLOW_BUILDER_SERVICES_CLASS_NAME = "org.springframework.webflow.engine.builder.support.FlowBuilderServices"; private static final String FLOW_REGISTRY_FACTORY_BEAN_CLASS_NAME = "org.springframework.webflow.config.FlowRegistryFactoryBean"; private static final String MVC_VIEW_FACTORY_CREATOR_CLASS_NAME = "org.springframework.webflow.mvc.builder.MvcViewFactoryCreator"; @@ -151,11 +152,15 @@ class FlowRegistryBeanDefinitionParser extends AbstractSingleBeanDefinitionParse String conversionService = registerInfrastructureComponent(element, context, conversionServiceBuilder); flowBuilderServicesBuilder.addPropertyReference("conversionService", conversionService); - BeanDefinitionBuilder expressionParserBuilder = BeanDefinitionBuilder - .genericBeanDefinition(DEFAULT_EXPRESSION_PARSER_FACTORY_CLASS_NAME); - expressionParserBuilder.setFactoryMethod("getExpressionParser"); - expressionParserBuilder.addConstructorArgReference(conversionService); - String expressionParser = registerInfrastructureComponent(element, context, expressionParserBuilder); + BeanDefinitionBuilder springElExpressionParserBuilder = BeanDefinitionBuilder + .genericBeanDefinition(SPRING_EL_EXPRESSION_PARSER_CLASS_NAME); + BeanDefinitionBuilder webFlowElExpressionParserBuilder = BeanDefinitionBuilder + .genericBeanDefinition(WEB_FLOW_SPRING_EL_EXPRESSION_PARSER_CLASS_NAME); + webFlowElExpressionParserBuilder + .addConstructorArgValue(springElExpressionParserBuilder.getBeanDefinition()); + + String expressionParser = registerInfrastructureComponent(element, context, + webFlowElExpressionParserBuilder); flowBuilderServicesBuilder.addPropertyReference("expressionParser", expressionParser); BeanDefinitionBuilder viewFactoryCreatorBuilder = BeanDefinitionBuilder 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 deleted file mode 100644 index 57e96bf2..00000000 --- a/spring-webflow/src/main/java/org/springframework/webflow/expression/DefaultExpressionParserFactory.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * 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.webflow.expression; - -import javax.el.ExpressionFactory; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.binding.convert.ConversionService; -import org.springframework.binding.expression.ExpressionParser; -import org.springframework.binding.expression.el.DefaultExpressionFactoryUtils; -import org.springframework.util.ClassUtils; -import org.springframework.webflow.expression.el.WebFlowELExpressionParser; - -/** - * Static factory that returns the default {@link ExpressionParser} used by Spring Web Flow. Marked final with a private - * constructor to prevent subclassing. - *

- * This factory employs the following algorithm when the returned ExpressionParser instance is used for the first time: - *

    - *
  • If a Unified EL implementation is configured for the VM, make a {@link WebFlowELExpressionParser} the default. - *
  • If no Unified EL implementation is configured and OGNL is configured, make a {@link WebFlowOgnlExpressionParser} - * the default. - *
  • If neither Unified EL or OGNL are configured, throw an IllegalStateException with a nice error message. - *
- * - * @author Keith Donald - * @author Erwin Vervaet - */ -public final class DefaultExpressionParserFactory { - - private static final Log logger = LogFactory.getLog(DefaultExpressionParserFactory.class); - - /** - * The singleton instance of the default expression parser. - */ - private static ExpressionParser INSTANCE; - - // static factory - not instantiable - private DefaultExpressionParserFactory() { - } - - /** - * Returns the default expression parser for Spring Web Flow. The returned instance is a cached thread-safe object. - * @return the expression parser - */ - public static synchronized ExpressionParser getExpressionParser() { - return getDefaultExpressionParser(); - } - - /** - * Returns the default expression parser for Spring Web Flow configured with the provided ConversionService for type - * conversion. The returned instance is a thread-safe object. - * @param conversionService the conversionService - * @return the expression parser - */ - public static synchronized ExpressionParser getExpressionParser(final ConversionService conversionService) { - return createDefaultExpressionParser(conversionService); - } - - /** - * Returns the default expression parser, creating it if necessary. - * @return the default expression parser - */ - private static synchronized ExpressionParser getDefaultExpressionParser() { - if (INSTANCE == null) { - INSTANCE = createDefaultExpressionParser(null); - if (logger.isDebugEnabled()) { - logger.debug("Initialized shared default Web Flow ExpressionParser " + INSTANCE); - } - } - return INSTANCE; - } - - /** - * Create the default expression parser. This implementation tries EL first, then OGNL if EL is not configured. - * @return the default Web Flow expression parser - */ - private static ExpressionParser createDefaultExpressionParser(ConversionService conversionService) - throws IllegalStateException { - try { - ExpressionFactory elFactory = DefaultExpressionFactoryUtils.createExpressionFactory(); - WebFlowELExpressionParser expressionParser = new WebFlowELExpressionParser(elFactory); - if (conversionService != null) { - expressionParser.setConversionService(conversionService); - } - return expressionParser; - } catch (Exception e) { - try { - ClassUtils.forName("ognl.Ognl", DefaultExpressionParserFactory.class.getClassLoader()); - WebFlowOgnlExpressionParser expressionParser = new WebFlowOgnlExpressionParser(); - if (conversionService != null) { - expressionParser.setConversionService(conversionService); - } - return expressionParser; - } catch (ClassNotFoundException ex) { - IllegalStateException ise = new IllegalStateException( - "Unable to create the default expression parser for Spring Web Flow: Neither a Unified EL implementation or OGNL could be found."); - ise.initCause(ex); - throw ise; - } catch (NoClassDefFoundError ex) { - IllegalStateException ise = new IllegalStateException( - "Unable to create the default expression parser for Spring Web Flow: Neither a Unified EL implementation or OGNL could be found."); - ise.initCause(ex); - throw ise; - } - } - } -} \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/expression/spel/ActionPropertyAccessor.java b/spring-webflow/src/main/java/org/springframework/webflow/expression/spel/ActionPropertyAccessor.java new file mode 100644 index 00000000..ceda9029 --- /dev/null +++ b/spring-webflow/src/main/java/org/springframework/webflow/expression/spel/ActionPropertyAccessor.java @@ -0,0 +1,61 @@ +/* + * Copyright 2002-2010 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.webflow.expression.spel; + +import org.springframework.expression.AccessException; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.PropertyAccessor; +import org.springframework.expression.TypedValue; +import org.springframework.webflow.action.MultiAction; +import org.springframework.webflow.execution.Action; +import org.springframework.webflow.execution.AnnotatedAction; + +/** + *

+ * Spring EL Property Accessor that allows invocation of methods against a resolved Web Flow action, typically a + * {@link MultiAction} in expressions. + *

+ * + * @see org.springframework.webflow.action.EvaluateAction + * + * @author Rossen Stoyanchev + * @since 2.1 + */ +public class ActionPropertyAccessor implements PropertyAccessor { + + public Class[] getSpecificTargetClasses() { + return new Class[] { Action.class }; + } + + public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException { + return true; + } + + public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException { + AnnotatedAction annotated = new AnnotatedAction((Action) target); + annotated.setMethod(name); + return new TypedValue(annotated); + } + + public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException { + return false; + } + + public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException { + throw new AccessException("The Action cannot be set with an expression."); + } + +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/expression/spel/BeanFactoryPropertyAccessor.java b/spring-webflow/src/main/java/org/springframework/webflow/expression/spel/BeanFactoryPropertyAccessor.java new file mode 100644 index 00000000..19c48581 --- /dev/null +++ b/spring-webflow/src/main/java/org/springframework/webflow/expression/spel/BeanFactoryPropertyAccessor.java @@ -0,0 +1,69 @@ +/* + * Copyright 2002-2010 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.webflow.expression.spel; + +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.support.StaticListableBeanFactory; +import org.springframework.expression.AccessException; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.PropertyAccessor; +import org.springframework.expression.TypedValue; +import org.springframework.webflow.execution.RequestContext; +import org.springframework.webflow.execution.RequestContextHolder; + +/** + * Spring EL PropertyAccessor for reading beans in a {@link org.springframework.beans.factory.BeanFactory}. + * + * @author Rossen Stoyanchev + * @since 2.1 + */ +public class BeanFactoryPropertyAccessor implements PropertyAccessor { + + private static final BeanFactory EMPTY_BEAN_FACTORY = new StaticListableBeanFactory(); + + public Class[] getSpecificTargetClasses() { + return null; + } + + public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException { + return getBeanFactory().containsBean(name); + } + + public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException { + return new TypedValue(getBeanFactory().getBean(name)); + } + + public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException { + return false; + } + + public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException { + throw new AccessException("Beans in a BeanFactory are read-only"); + } + + protected BeanFactory getBeanFactory() { + RequestContext requestContext = RequestContextHolder.getRequestContext(); + if (requestContext != null) { + BeanFactory beanFactory = requestContext.getActiveFlow().getApplicationContext(); + if (beanFactory != null) { + return beanFactory; + } + } + return EMPTY_BEAN_FACTORY; + } + +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/expression/spel/FlowVariablePropertyAccessor.java b/spring-webflow/src/main/java/org/springframework/webflow/expression/spel/FlowVariablePropertyAccessor.java new file mode 100644 index 00000000..bdc70c35 --- /dev/null +++ b/spring-webflow/src/main/java/org/springframework/webflow/expression/spel/FlowVariablePropertyAccessor.java @@ -0,0 +1,95 @@ +/* + * Copyright 2002-2010 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.webflow.expression.spel; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.expression.AccessException; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.PropertyAccessor; +import org.springframework.expression.TypedValue; +import org.springframework.expression.spel.support.ReflectivePropertyAccessor; +import org.springframework.webflow.execution.RequestContext; +import org.springframework.webflow.execution.RequestContextHolder; + +/** + *

+ * Spring EL PropertyAccessor that enables use of the following reserved variables in expressions: + *

+ * + *
+ * currentUser
+ * flowRequestContext
+ * resourceBundle
+ * 
+ * + *

+ * Note that any property of {@link RequestContext} (e.g. flowScope, requestParameters, etc.) may also be used in + * expressions. Such properties are already handled by the {@link ReflectivePropertyAccessor}. + *

+ * + * @author Rossen Stoyanchev + * @since 2.1 + */ +public class FlowVariablePropertyAccessor implements PropertyAccessor { + + private static Map variables = new HashMap(); + + static { + variables.put("currentUser", new FlowVariableAccessor() { + public Object getVariable() { + return RequestContextHolder.getRequestContext().getExternalContext().getCurrentUser(); + } + }); + variables.put("flowRequestContext", new FlowVariableAccessor() { + public Object getVariable() { + return RequestContextHolder.getRequestContext(); + } + }); + variables.put("resourceBundle", new FlowVariableAccessor() { + public Object getVariable() { + return RequestContextHolder.getRequestContext().getActiveFlow().getApplicationContext(); + } + }); + } + + public Class[] getSpecificTargetClasses() { + return null; + } + + public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException { + return variables.containsKey(name); + } + + public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException { + FlowVariableAccessor var = (FlowVariableAccessor) variables.get(name); + return new TypedValue(var.getVariable()); + } + + public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException { + return false; + } + + public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException { + throw new AccessException(name + " is a flow reserved word and cannot be set with an expression."); + } + + private interface FlowVariableAccessor { + Object getVariable(); + } + +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/expression/spel/MapAdaptablePropertyAccessor.java b/spring-webflow/src/main/java/org/springframework/webflow/expression/spel/MapAdaptablePropertyAccessor.java new file mode 100644 index 00000000..e66bd72a --- /dev/null +++ b/spring-webflow/src/main/java/org/springframework/webflow/expression/spel/MapAdaptablePropertyAccessor.java @@ -0,0 +1,55 @@ +/* + * Copyright 2002-2010 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.webflow.expression.spel; + +import org.springframework.binding.collection.MapAdaptable; +import org.springframework.expression.AccessException; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.PropertyAccessor; +import org.springframework.expression.TypedValue; +import org.springframework.webflow.core.collection.MutableAttributeMap; + +/** + * Spring EL PropertyAccessor for reading from {@link MapAdaptable} and writing to {@link MutableAttributeMap}. + * + * @author Rossen Stoyanchev + * @since 2.1 + */ +public class MapAdaptablePropertyAccessor implements PropertyAccessor { + + public Class[] getSpecificTargetClasses() { + return new Class[] { MapAdaptable.class }; + } + + public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException { + return true; + } + + public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException { + MapAdaptable map = (MapAdaptable) target; + return new TypedValue(map.asMap().get(name)); + } + + public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException { + return (target instanceof MutableAttributeMap); + } + + public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException { + MutableAttributeMap map = (MutableAttributeMap) target; + map.put(name, newValue); + } + +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/expression/spel/MessageSourcePropertyAccessor.java b/spring-webflow/src/main/java/org/springframework/webflow/expression/spel/MessageSourcePropertyAccessor.java new file mode 100644 index 00000000..6312a480 --- /dev/null +++ b/spring-webflow/src/main/java/org/springframework/webflow/expression/spel/MessageSourcePropertyAccessor.java @@ -0,0 +1,76 @@ +/* + * Copyright 2002-2010 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.webflow.expression.spel; + +import java.util.Locale; + +import org.springframework.context.MessageSource; +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.expression.AccessException; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.PropertyAccessor; +import org.springframework.expression.TypedValue; +import org.springframework.webflow.execution.RequestContext; +import org.springframework.webflow.execution.RequestContextHolder; + +/** + *

+ * Spring EL PropertyAccessor that resolves messages from the {@link MessageSource} of the active Flow. The message + * source itself is accessible through the "resourceBundle" variable (see {@link FlowVariablePropertyAccessor}). To + * access a specific message use its key in one of the following ways: + *

+ * + *
+ * resourceBundle.myErrorCode
+ * resourceBundle['myErrorCode']
+ * 
+ * + * @author Rossen Stoyanchev + * @since 2.1 + */ +public class MessageSourcePropertyAccessor implements PropertyAccessor { + + public Class[] getSpecificTargetClasses() { + return new Class[] { MessageSource.class }; + } + + public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException { + return (getMessage(target, name) != null); + } + + public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException { + return new TypedValue(getMessage(target, name)); + } + + public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException { + return false; + } + + public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException { + throw new AccessException("The flow MessageSource is not writable."); + } + + private String getMessage(Object target, String name) { + return ((MessageSource) target).getMessage(name, null, null, getLocale()); + } + + private Locale getLocale() { + RequestContext requestContext = RequestContextHolder.getRequestContext(); + return (requestContext != null) ? requestContext.getExternalContext().getLocale() : LocaleContextHolder + .getLocale(); + } + +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/expression/spel/ScopeSearchingPropertyAccessor.java b/spring-webflow/src/main/java/org/springframework/webflow/expression/spel/ScopeSearchingPropertyAccessor.java new file mode 100644 index 00000000..ec130f12 --- /dev/null +++ b/spring-webflow/src/main/java/org/springframework/webflow/expression/spel/ScopeSearchingPropertyAccessor.java @@ -0,0 +1,76 @@ +/* + * Copyright 2004-2010 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.webflow.expression.spel; + +import org.springframework.expression.AccessException; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.PropertyAccessor; +import org.springframework.expression.TypedValue; +import org.springframework.webflow.core.collection.MutableAttributeMap; +import org.springframework.webflow.execution.RequestContext; + +/** + * Spring EL PropertyAccessor that searches through all Web Flow scopes. + * + * @author Rossen Stoyanchev + * @since 2.1 + */ +public class ScopeSearchingPropertyAccessor implements PropertyAccessor { + + public Class[] getSpecificTargetClasses() { + return new Class[] { RequestContext.class }; + } + + public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException { + return (findScopeForAttribute((RequestContext) target, name) != null); + } + + public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException { + MutableAttributeMap scope = findScopeForAttribute((RequestContext) target, name); + return (scope != null) ? new TypedValue(scope.get(name)) : null; + } + + public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException { + return (findScopeForAttribute((RequestContext) target, name) != null); + } + + public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException { + MutableAttributeMap scope = findScopeForAttribute((RequestContext) target, name); + if (scope != null) { + scope.put(name, newValue); + } + } + + private MutableAttributeMap findScopeForAttribute(RequestContext requestContext, String name) { + if (requestContext.getRequestScope().contains(name)) { + return requestContext.getRequestScope(); + } + if (requestContext.getFlashScope().contains(name)) { + return requestContext.getFlashScope(); + } + if (requestContext.inViewState() && requestContext.getViewScope().contains(name)) { + return requestContext.getViewScope(); + } + if (requestContext.getFlowScope().contains(name)) { + return requestContext.getFlowScope(); + } + if (requestContext.getConversationScope().contains(name)) { + return requestContext.getConversationScope(); + } + return null; + } + +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/expression/spel/WebFlowSpringELExpressionParser.java b/spring-webflow/src/main/java/org/springframework/webflow/expression/spel/WebFlowSpringELExpressionParser.java new file mode 100644 index 00000000..8e6e38c5 --- /dev/null +++ b/spring-webflow/src/main/java/org/springframework/webflow/expression/spel/WebFlowSpringELExpressionParser.java @@ -0,0 +1,39 @@ +/* + * Copyright 2002-2010 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.webflow.expression.spel; + +import org.springframework.binding.expression.spel.SpringELExpressionParser; +import org.springframework.expression.spel.standard.SpelExpressionParser; + +/** + * A sub-class for {@link SpringELExpressionParser} that registers Web Flow specific Spring EL PropertyAccessors. + * + * @author Rossen Stoyanchev + * @since 2.1 + */ +public class WebFlowSpringELExpressionParser extends SpringELExpressionParser { + + public WebFlowSpringELExpressionParser(SpelExpressionParser expressionParser) { + super(expressionParser); + addPropertyAccessor(new MessageSourcePropertyAccessor()); + addPropertyAccessor(new FlowVariablePropertyAccessor()); + addPropertyAccessor(new MapAdaptablePropertyAccessor()); + addPropertyAccessor(new ScopeSearchingPropertyAccessor()); + addPropertyAccessor(new BeanFactoryPropertyAccessor()); + addPropertyAccessor(new ActionPropertyAccessor()); + } + +} 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 4417f490..ca9ec363 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 @@ -2,8 +2,9 @@ package org.springframework.webflow.test; import org.springframework.binding.convert.service.DefaultConversionService; import org.springframework.context.support.StaticApplicationContext; +import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.webflow.engine.builder.support.FlowBuilderServices; -import org.springframework.webflow.expression.DefaultExpressionParserFactory; +import org.springframework.webflow.expression.spel.WebFlowSpringELExpressionParser; /** * Factory that encapsulates configuration of default flow builder services for a test environment. @@ -17,7 +18,7 @@ public class TestFlowBuilderServicesFactory { FlowBuilderServices services = new FlowBuilderServices(); services.setViewFactoryCreator(new MockViewFactoryCreator()); services.setConversionService(new DefaultConversionService()); - services.setExpressionParser(DefaultExpressionParserFactory.getExpressionParser()); + services.setExpressionParser(new WebFlowSpringELExpressionParser(new SpelExpressionParser())); 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 33a603d1..7fc343d9 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 @@ -12,12 +12,12 @@ import org.springframework.binding.convert.ConversionService; import org.springframework.binding.convert.service.DefaultConversionService; import org.springframework.binding.expression.Expression; import org.springframework.binding.expression.ExpressionParser; +import org.springframework.binding.expression.spel.SpringELExpressionParser; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.webflow.engine.builder.BinderConfiguration; import org.springframework.webflow.engine.builder.ViewFactoryCreator; import org.springframework.webflow.engine.builder.support.FlowBuilderServices; import org.springframework.webflow.execution.ViewFactory; -import org.springframework.webflow.expression.el.WebFlowELExpressionParser; import org.springframework.webflow.mvc.builder.MvcViewFactoryCreator; public class FlowBuilderServicesBeanDefinitionParserTests extends TestCase { @@ -32,7 +32,7 @@ public class FlowBuilderServicesBeanDefinitionParserTests extends TestCase { public void testFlowBuilderServicesDefaultConfig() { builderServices = (FlowBuilderServices) context.getBean("flowBuilderServicesDefault"); assertNotNull(builderServices); - assertTrue(builderServices.getExpressionParser() instanceof WebFlowELExpressionParser); + assertTrue(builderServices.getExpressionParser() instanceof SpringELExpressionParser); assertTrue(builderServices.getViewFactoryCreator() instanceof MvcViewFactoryCreator); assertTrue(builderServices.getConversionService() instanceof DefaultConversionService); assertFalse(builderServices.getDevelopment()); @@ -41,7 +41,7 @@ public class FlowBuilderServicesBeanDefinitionParserTests extends TestCase { public void testFlowBuilderServicesAllCustomized() { builderServices = (FlowBuilderServices) context.getBean("flowBuilderServicesAllCustom"); assertNotNull(builderServices); - assertTrue(builderServices.getExpressionParser() instanceof WebFlowELExpressionParser); + assertTrue(builderServices.getExpressionParser() instanceof SpringELExpressionParser); assertTrue(builderServices.getViewFactoryCreator() instanceof TestViewFactoryCreator); assertTrue(builderServices.getConversionService() instanceof TestConversionService); assertTrue(builderServices.getDevelopment()); @@ -51,8 +51,8 @@ public class FlowBuilderServicesBeanDefinitionParserTests extends TestCase { builderServices = (FlowBuilderServices) context.getBean("flowBuilderServicesConversionServiceCustom"); assertNotNull(builderServices); assertTrue(builderServices.getConversionService() instanceof TestConversionService); - assertTrue(builderServices.getExpressionParser() instanceof WebFlowELExpressionParser); - assertTrue(((WebFlowELExpressionParser) builderServices.getExpressionParser()).getConversionService() instanceof TestConversionService); + assertTrue(builderServices.getExpressionParser() instanceof SpringELExpressionParser); + assertNotNull(((SpringELExpressionParser) builderServices.getExpressionParser()).getConversionService()); assertTrue(builderServices.getViewFactoryCreator() instanceof MvcViewFactoryCreator); assertFalse(builderServices.getDevelopment()); } diff --git a/spring-webflow/src/test/java/org/springframework/webflow/config/FlowRegistryBeanDefinitionParserTests.java b/spring-webflow/src/test/java/org/springframework/webflow/config/FlowRegistryBeanDefinitionParserTests.java index e787ee2c..21b482de 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/config/FlowRegistryBeanDefinitionParserTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/config/FlowRegistryBeanDefinitionParserTests.java @@ -6,13 +6,13 @@ import java.util.Map; import junit.framework.TestCase; import org.springframework.binding.convert.service.DefaultConversionService; +import org.springframework.binding.expression.spel.SpringELExpressionParser; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.webflow.definition.FlowDefinition; import org.springframework.webflow.definition.registry.FlowDefinitionConstructionException; import org.springframework.webflow.definition.registry.FlowDefinitionRegistry; import org.springframework.webflow.definition.registry.NoSuchFlowDefinitionException; import org.springframework.webflow.engine.builder.support.FlowBuilderServices; -import org.springframework.webflow.expression.el.WebFlowELExpressionParser; import org.springframework.webflow.mvc.builder.MvcViewFactoryCreator; public class FlowRegistryBeanDefinitionParserTests extends TestCase { @@ -63,7 +63,7 @@ public class FlowRegistryBeanDefinitionParserTests extends TestCase { while (i.hasNext()) { FlowBuilderServices builderServices = (FlowBuilderServices) i.next(); assertNotNull(builderServices); - assertTrue(builderServices.getExpressionParser() instanceof WebFlowELExpressionParser); + assertTrue(builderServices.getExpressionParser() instanceof SpringELExpressionParser); assertTrue(builderServices.getViewFactoryCreator() instanceof MvcViewFactoryCreator); assertTrue(builderServices.getConversionService() instanceof DefaultConversionService); assertFalse(builderServices.getDevelopment()); diff --git a/spring-webflow/src/test/java/org/springframework/webflow/config/flow-builder-services.xml b/spring-webflow/src/test/java/org/springframework/webflow/config/flow-builder-services.xml index 8999f625..505fb3e2 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/config/flow-builder-services.xml +++ b/spring-webflow/src/test/java/org/springframework/webflow/config/flow-builder-services.xml @@ -18,7 +18,11 @@ - + + + + + diff --git a/spring-webflow/src/test/java/org/springframework/webflow/engine/EndStateTests.java b/spring-webflow/src/test/java/org/springframework/webflow/engine/EndStateTests.java index f19d4095..53eae243 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/engine/EndStateTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/engine/EndStateTests.java @@ -24,6 +24,7 @@ import org.springframework.binding.expression.support.AbstractGetValueExpression import org.springframework.binding.expression.support.FluentParserContext; import org.springframework.binding.mapping.impl.DefaultMapper; import org.springframework.binding.mapping.impl.DefaultMapping; +import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.webflow.core.collection.MutableAttributeMap; import org.springframework.webflow.engine.support.DefaultTargetStateResolver; import org.springframework.webflow.engine.support.MockTransitionCriteria; @@ -31,7 +32,7 @@ import org.springframework.webflow.execution.Action; import org.springframework.webflow.execution.Event; import org.springframework.webflow.execution.FlowExecutionException; import org.springframework.webflow.execution.RequestContext; -import org.springframework.webflow.expression.DefaultExpressionParserFactory; +import org.springframework.webflow.expression.spel.WebFlowSpringELExpressionParser; import org.springframework.webflow.test.MockFlowExecutionContext; import org.springframework.webflow.test.MockFlowSession; import org.springframework.webflow.test.MockRequestControlContext; @@ -79,7 +80,7 @@ public class EndStateTests extends TestCase { }; EndState state = new EndState(flow, "end"); DefaultMapper mapper = new DefaultMapper(); - ExpressionParser parser = DefaultExpressionParserFactory.getExpressionParser(); + ExpressionParser parser = new WebFlowSpringELExpressionParser(new SpelExpressionParser()); Expression x = parser.parseExpression("flowScope.x", new FluentParserContext().evaluate(RequestContext.class)); Expression y = parser.parseExpression("y", new FluentParserContext().evaluate(MutableAttributeMap.class)); mapper.addMapping(new DefaultMapping(x, y)); diff --git a/spring-webflow/src/test/java/org/springframework/webflow/engine/FlowTests.java b/spring-webflow/src/test/java/org/springframework/webflow/engine/FlowTests.java index f0267163..da951e8d 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/engine/FlowTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/engine/FlowTests.java @@ -25,6 +25,7 @@ import org.springframework.binding.expression.support.FluentParserContext; import org.springframework.binding.mapping.impl.DefaultMapper; import org.springframework.binding.mapping.impl.DefaultMapping; import org.springframework.context.support.GenericApplicationContext; +import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.webflow.TestException; import org.springframework.webflow.action.TestMultiAction; import org.springframework.webflow.core.collection.AttributeMap; @@ -37,7 +38,7 @@ import org.springframework.webflow.execution.Event; import org.springframework.webflow.execution.FlowExecutionException; import org.springframework.webflow.execution.RequestContext; import org.springframework.webflow.execution.TestAction; -import org.springframework.webflow.expression.DefaultExpressionParserFactory; +import org.springframework.webflow.expression.spel.WebFlowSpringELExpressionParser; import org.springframework.webflow.test.MockRequestControlContext; /** @@ -209,7 +210,7 @@ public class FlowTests extends TestCase { public void testStartWithMapper() { DefaultMapper attributeMapper = new DefaultMapper(); - ExpressionParser parser = DefaultExpressionParserFactory.getExpressionParser(); + ExpressionParser parser = new WebFlowSpringELExpressionParser(new SpelExpressionParser()); Expression x = parser.parseExpression("attr", new FluentParserContext().evaluate(AttributeMap.class)); Expression y = parser.parseExpression("flowScope.attr", new FluentParserContext() .evaluate(RequestContext.class)); @@ -224,7 +225,7 @@ public class FlowTests extends TestCase { public void testStartWithMapperButNoInput() { DefaultMapper attributeMapper = new DefaultMapper(); - ExpressionParser parser = DefaultExpressionParserFactory.getExpressionParser(); + ExpressionParser parser = new WebFlowSpringELExpressionParser(new SpelExpressionParser()); Expression x = parser.parseExpression("attr", new FluentParserContext().evaluate(AttributeMap.class)); Expression y = parser.parseExpression("flowScope.attr", new FluentParserContext() .evaluate(RequestContext.class)); @@ -314,7 +315,7 @@ public class FlowTests extends TestCase { public void testEndWithOutputMapper() { DefaultMapper attributeMapper = new DefaultMapper(); - ExpressionParser parser = DefaultExpressionParserFactory.getExpressionParser(); + ExpressionParser parser = new WebFlowSpringELExpressionParser(new SpelExpressionParser()); Expression x = parser.parseExpression("flowScope.attr", new FluentParserContext() .evaluate(RequestContext.class)); Expression y = parser.parseExpression("attr", new FluentParserContext().evaluate(MutableAttributeMap.class)); diff --git a/spring-webflow/src/test/java/org/springframework/webflow/engine/builder/support/TextToTargetStateResolverTests.java b/spring-webflow/src/test/java/org/springframework/webflow/engine/builder/support/TextToTargetStateResolverTests.java index 30452002..2d159039 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/engine/builder/support/TextToTargetStateResolverTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/engine/builder/support/TextToTargetStateResolverTests.java @@ -40,7 +40,7 @@ public class TextToTargetStateResolverTests extends TestCase { } public void testDynamic() throws Exception { - String expression = "${flowScope.lastState}"; + String expression = "#{flowScope.lastState}"; TargetStateResolver resolver = (TargetStateResolver) converter.convertSourceToTargetClass(expression, TargetStateResolver.class); MockRequestContext context = new MockRequestContext(); diff --git a/spring-webflow/src/test/java/org/springframework/webflow/engine/builder/support/TextToTransitionCriteriaTests.java b/spring-webflow/src/test/java/org/springframework/webflow/engine/builder/support/TextToTransitionCriteriaTests.java index 854bb3c3..de6bfb29 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/engine/builder/support/TextToTransitionCriteriaTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/engine/builder/support/TextToTransitionCriteriaTests.java @@ -62,7 +62,7 @@ public class TextToTransitionCriteriaTests extends TestCase { } public void testTrueEvaluation() throws Exception { - String expression = "${flowScope.foo == 'bar'}"; + String expression = "#{flowScope.foo == 'bar'}"; TransitionCriteria criterion = (TransitionCriteria) converter.convertSourceToTargetClass(expression, TransitionCriteria.class); RequestContext ctx = getRequestContext(); @@ -70,7 +70,7 @@ public class TextToTransitionCriteriaTests extends TestCase { } public void testFalseEvaluation() throws Exception { - String expression = "${flowScope.foo != 'bar'}"; + String expression = "#{flowScope.foo != 'bar'}"; TransitionCriteria criterion = (TransitionCriteria) converter.convertSourceToTargetClass(expression, TransitionCriteria.class); RequestContext ctx = getRequestContext(); @@ -78,7 +78,7 @@ public class TextToTransitionCriteriaTests extends TestCase { } public void testNonStringEvaluation() throws Exception { - String expression = "${3 + 4}"; + String expression = "#{3 + 4}"; TransitionCriteria criterion = (TransitionCriteria) converter.convertSourceToTargetClass(expression, TransitionCriteria.class); MockRequestContext ctx = getRequestContext(); @@ -87,7 +87,7 @@ public class TextToTransitionCriteriaTests extends TestCase { } public void testCurrenEventEval() throws Exception { - String expression = "${currentEvent == 'submit'}"; + String expression = "#{currentEvent.id == 'submit'}"; TransitionCriteria criterion = (TransitionCriteria) converter.convertSourceToTargetClass(expression, TransitionCriteria.class); MockRequestContext ctx = getRequestContext(); diff --git a/spring-webflow/src/test/java/org/springframework/webflow/expression/DefaultExpressionParserFactoryTests.java b/spring-webflow/src/test/java/org/springframework/webflow/expression/DefaultExpressionParserFactoryTests.java deleted file mode 100644 index dab6127e..00000000 --- a/spring-webflow/src/test/java/org/springframework/webflow/expression/DefaultExpressionParserFactoryTests.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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.webflow.expression; - -import junit.framework.TestCase; - -import org.springframework.binding.expression.ExpressionParser; - -/** - * Unit tests for {@link DefaultExpressionParserFactory}. - */ -public class DefaultExpressionParserFactoryTests extends TestCase { - - public void testGetDefaultExpressionParser() { - ExpressionParser parser = DefaultExpressionParserFactory.getExpressionParser(); - assertNotNull(parser); - } - - // public void testGetDefaultExpressionParserConversionService() { - // DefaultConversionService conversionService = new DefaultConversionService(); - // ExpressionParser parser = DefaultExpressionParserFactory.getExpressionParser(conversionService); - // Expression exp = parser.parseExpression("datum3", new FluentParserContext().expectResult(String.class)); - // TestBean context = new TestBean(); - // Calendar cal = Calendar.getInstance(); - // cal.set(2008, 1, 1); - // exp.setValue(context, cal.getTime()); - // String string = (String) exp.getValue(context); - // assertEquals(null, string); - // } -} diff --git a/spring-webflow/src/test/java/org/springframework/webflow/expression/el/WebFlowELExpressionParserTests.java b/spring-webflow/src/test/java/org/springframework/webflow/expression/el/WebFlowELExpressionParserTests.java index 24541d9f..f943c0eb 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/expression/el/WebFlowELExpressionParserTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/expression/el/WebFlowELExpressionParserTests.java @@ -5,8 +5,8 @@ import java.util.Locale; import junit.framework.TestCase; +import org.jboss.el.ExpressionFactoryImpl; import org.springframework.binding.expression.Expression; -import org.springframework.binding.expression.el.DefaultExpressionFactoryUtils; import org.springframework.binding.expression.support.FluentParserContext; import org.springframework.context.support.StaticApplicationContext; import org.springframework.webflow.TestBean; @@ -24,8 +24,7 @@ import org.springframework.webflow.test.MockRequestContext; import org.springframework.webflow.test.MockRequestControlContext; public class WebFlowELExpressionParserTests extends TestCase { - private WebFlowELExpressionParser parser = new WebFlowELExpressionParser(DefaultExpressionFactoryUtils - .createExpressionFactory()); + private WebFlowELExpressionParser parser = new WebFlowELExpressionParser(new ExpressionFactoryImpl()); public void testResolveMap() { LocalAttributeMap map = new LocalAttributeMap(); diff --git a/spring-webflow/src/test/java/org/springframework/webflow/expression/spel/FlowVariablePropertyAccessorTests.java b/spring-webflow/src/test/java/org/springframework/webflow/expression/spel/FlowVariablePropertyAccessorTests.java new file mode 100644 index 00000000..2d55dd52 --- /dev/null +++ b/spring-webflow/src/test/java/org/springframework/webflow/expression/spel/FlowVariablePropertyAccessorTests.java @@ -0,0 +1,70 @@ +/* + * Copyright 2002-2010 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.webflow.expression.spel; + +import junit.framework.TestCase; + +import org.springframework.context.support.StaticApplicationContext; +import org.springframework.expression.AccessException; +import org.springframework.webflow.engine.Flow; +import org.springframework.webflow.execution.RequestContextHolder; +import org.springframework.webflow.test.MockExternalContext; +import org.springframework.webflow.test.MockRequestContext; + +public class FlowVariablePropertyAccessorTests extends TestCase { + + private FlowVariablePropertyAccessor accessor = new FlowVariablePropertyAccessor(); + + private MockRequestContext requestContext; + + protected void setUp() throws Exception { + requestContext = new MockRequestContext(); + RequestContextHolder.setRequestContext(requestContext); + } + + protected void tearDown() throws Exception { + RequestContextHolder.setRequestContext(null); + } + + public void testFlowRequestContext() throws Exception { + assertTrue(accessor.canRead(null, null, "flowRequestContext")); + assertEquals(requestContext, accessor.read(null, null, "flowRequestContext").getValue()); + } + + public void testCurrentUser() throws Exception { + MockExternalContext externalContext = (MockExternalContext) requestContext.getExternalContext(); + externalContext.setCurrentUser("joe"); + assertTrue(accessor.canRead(null, null, "currentUser")); + assertEquals(externalContext.getCurrentUser(), accessor.read(null, null, "currentUser").getValue()); + } + + public void testResourceBundle() throws Exception { + Flow flow = (Flow) requestContext.getActiveFlow(); + flow.setApplicationContext(new StaticApplicationContext()); + assertTrue(accessor.canRead(null, null, "resourceBundle")); + assertNotNull(accessor.read(null, null, "resourceBundle").getValue()); + assertEquals(requestContext.getActiveFlow().getApplicationContext(), accessor + .read(null, null, "resourceBundle").getValue()); + } + + public void testWrite() throws Exception { + assertFalse(accessor.canWrite(null, null, "anyName")); + try { + accessor.write(null, null, "anyName", "anyValue"); + } catch (AccessException e) { + } + } +} diff --git a/spring-webflow/src/test/java/org/springframework/webflow/expression/spel/ScopeSearchingPropertyAccessorTests.java b/spring-webflow/src/test/java/org/springframework/webflow/expression/spel/ScopeSearchingPropertyAccessorTests.java new file mode 100644 index 00000000..e340f314 --- /dev/null +++ b/spring-webflow/src/test/java/org/springframework/webflow/expression/spel/ScopeSearchingPropertyAccessorTests.java @@ -0,0 +1,87 @@ +/* + * Copyright 2004-2010 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.webflow.expression.spel; + +import junit.framework.TestCase; + +import org.springframework.expression.TypedValue; +import org.springframework.expression.spel.support.StandardEvaluationContext; +import org.springframework.webflow.engine.ViewState; +import org.springframework.webflow.execution.RequestContext; +import org.springframework.webflow.execution.View; +import org.springframework.webflow.execution.ViewFactory; +import org.springframework.webflow.test.MockFlowSession; +import org.springframework.webflow.test.MockRequestContext; + +public class ScopeSearchingPropertyAccessorTests extends TestCase { + + private ScopeSearchingPropertyAccessor accessor = new ScopeSearchingPropertyAccessor(); + + private MockRequestContext requestContext; + + protected void setUp() throws Exception { + requestContext = new MockRequestContext(); + } + + public void testGetSpecificTargetClasses() throws Exception { + Class[] classes = accessor.getSpecificTargetClasses(); + assertEquals(1, classes.length); + assertEquals(RequestContext.class, classes[0]); + } + + public void testGetValue() throws Exception { + Object bean = new Object(); + requestContext.getConversationScope().put("myBean", bean); + TypedValue actual = accessor.read(new StandardEvaluationContext(), requestContext, "myBean"); + assertSame(bean, actual.getValue()); + + bean = new Object(); + requestContext.getFlowScope().put("myBean", bean); + actual = accessor.read(new StandardEvaluationContext(), requestContext, "myBean"); + assertSame(bean, actual.getValue()); + + bean = new Object(); + initView(requestContext); + requestContext.getViewScope().put("myBean", bean); + actual = accessor.read(new StandardEvaluationContext(), requestContext, "myBean"); + unsetView(requestContext); + assertSame(bean, actual.getValue()); + + bean = new Object(); + requestContext.getFlashScope().put("myBean", bean); + actual = accessor.read(new StandardEvaluationContext(), requestContext, "myBean"); + assertSame(bean, actual.getValue()); + + bean = new Object(); + requestContext.getRequestScope().put("myBean", bean); + actual = accessor.read(new StandardEvaluationContext(), requestContext, "myBean"); + assertSame(bean, actual.getValue()); + } + + protected void initView(MockRequestContext requestContext) { + ((MockFlowSession) requestContext.getFlowExecutionContext().getActiveSession()).setState(new ViewState( + requestContext.getRootFlow(), "view", new ViewFactory() { + public View getView(RequestContext context) { + throw new UnsupportedOperationException("Not implemented"); + } + })); + } + + protected void unsetView(MockRequestContext requestContext) { + ((MockFlowSession) requestContext.getFlowExecutionContext().getActiveSession()).setState(null); + } + +} diff --git a/spring-webflow/src/test/java/org/springframework/webflow/expression/spel/WebFlowSpringELExpressionParserTests.java b/spring-webflow/src/test/java/org/springframework/webflow/expression/spel/WebFlowSpringELExpressionParserTests.java new file mode 100644 index 00000000..cc508fda --- /dev/null +++ b/spring-webflow/src/test/java/org/springframework/webflow/expression/spel/WebFlowSpringELExpressionParserTests.java @@ -0,0 +1,70 @@ +/* + * Copyright 2004-2010 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.webflow.expression.spel; + +import java.util.Locale; + +import junit.framework.TestCase; + +import org.springframework.binding.expression.Expression; +import org.springframework.binding.expression.ExpressionParser; +import org.springframework.binding.expression.support.FluentParserContext; +import org.springframework.context.support.StaticApplicationContext; +import org.springframework.context.support.StaticMessageSource; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.webflow.engine.Flow; +import org.springframework.webflow.execution.RequestContextHolder; +import org.springframework.webflow.test.MockExternalContext; +import org.springframework.webflow.test.MockRequestContext; + +public class WebFlowSpringELExpressionParserTests extends TestCase { + + private ExpressionParser parser = new WebFlowSpringELExpressionParser(new SpelExpressionParser()); + + private MockRequestContext requestContext; + + protected void setUp() throws Exception { + requestContext = new MockRequestContext(); + RequestContextHolder.setRequestContext(requestContext); + } + + public void testResourceBundleRead() throws Exception { + MockExternalContext externalContext = (MockExternalContext) requestContext.getExternalContext(); + externalContext.setLocale(Locale.ENGLISH); + + StaticApplicationContext applicationContext = new StaticApplicationContext(); + StaticMessageSource messageSource = applicationContext.getStaticMessageSource(); + messageSource.addMessage("myCode", externalContext.getLocale(), "myCode message"); + messageSource.addMessage("myCode.myCode", externalContext.getLocale(), "myCode myCode message"); + applicationContext.refresh(); + + Flow flow = (Flow) requestContext.getActiveFlow(); + flow.setApplicationContext(applicationContext); + + String expressionString = "#{resourceBundle.myCode}"; + Expression exp = parser.parseExpression(expressionString, new FluentParserContext().template()); + assertEquals("myCode message", exp.getValue(requestContext)); + + expressionString = "#{resourceBundle['myCode']}"; + exp = parser.parseExpression(expressionString, new FluentParserContext().template()); + assertEquals("myCode message", exp.getValue(requestContext)); + + expressionString = "#{resourceBundle['myCode.myCode']}"; + exp = parser.parseExpression(expressionString, new FluentParserContext().template()); + assertEquals("myCode myCode message", exp.getValue(requestContext)); + } + +} diff --git a/spring-webflow/src/test/java/org/springframework/webflow/mvc/portlet/PortletMvcViewTests.java b/spring-webflow/src/test/java/org/springframework/webflow/mvc/portlet/PortletMvcViewTests.java index 05b27e84..7a28a049 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/mvc/portlet/PortletMvcViewTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/mvc/portlet/PortletMvcViewTests.java @@ -7,6 +7,7 @@ import junit.framework.TestCase; import org.easymock.EasyMock; import org.springframework.binding.expression.support.StaticExpression; +import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.mock.web.MockServletContext; @@ -14,7 +15,7 @@ import org.springframework.mock.web.portlet.MockPortletContext; import org.springframework.mock.web.portlet.MockRenderRequest; import org.springframework.mock.web.portlet.MockRenderResponse; import org.springframework.web.servlet.ViewRendererServlet; -import org.springframework.webflow.expression.DefaultExpressionParserFactory; +import org.springframework.webflow.expression.spel.WebFlowSpringELExpressionParser; import org.springframework.webflow.mvc.view.AbstractMvcView; import org.springframework.webflow.mvc.view.MvcViewTests.BindBean; import org.springframework.webflow.test.MockFlowExecutionKey; @@ -56,7 +57,7 @@ public class PortletMvcViewTests extends TestCase { org.springframework.web.servlet.View mvcView = (org.springframework.web.servlet.View) EasyMock .createMock(org.springframework.web.servlet.View.class); AbstractMvcView view = new PortletMvcView(mvcView, context); - view.setExpressionParser(DefaultExpressionParserFactory.getExpressionParser()); + view.setExpressionParser(new WebFlowSpringELExpressionParser(new SpelExpressionParser())); view.setMessageCodesResolver(new WebFlowMessageCodesResolver()); view.processUserEvent(); assertEquals(true, bindBean.getBooleanProperty()); diff --git a/spring-webflow/src/test/java/org/springframework/webflow/mvc/view/DefaultBindingModelTests.java b/spring-webflow/src/test/java/org/springframework/webflow/mvc/view/DefaultBindingModelTests.java index d9ee3b29..2240f962 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/mvc/view/DefaultBindingModelTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/mvc/view/DefaultBindingModelTests.java @@ -1,11 +1,12 @@ package org.springframework.webflow.mvc.view; import org.springframework.binding.expression.ExpressionParser; -import org.springframework.webflow.expression.DefaultExpressionParserFactory; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.webflow.expression.spel.WebFlowSpringELExpressionParser; public class DefaultBindingModelTests extends AbstractBindingModelTests { protected ExpressionParser getExpressionParser() { - return DefaultExpressionParserFactory.getExpressionParser(); + return new WebFlowSpringELExpressionParser(new SpelExpressionParser()); } } 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 8bfc404e..ea87f8ea 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 @@ -21,8 +21,12 @@ import org.springframework.binding.convert.converters.StringToDate; import org.springframework.binding.convert.service.DefaultConversionService; import org.springframework.binding.expression.EvaluationException; import org.springframework.binding.expression.Expression; +import org.springframework.binding.expression.spel.SpringELExpressionParser; import org.springframework.binding.expression.support.StaticExpression; import org.springframework.binding.validation.ValidationContext; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.format.datetime.DateFormatter; +import org.springframework.format.support.FormattingConversionService; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.mock.web.MockMultipartFile; @@ -37,7 +41,7 @@ import org.springframework.webflow.engine.ViewState; import org.springframework.webflow.engine.builder.BinderConfiguration; import org.springframework.webflow.engine.builder.BinderConfiguration.Binding; import org.springframework.webflow.execution.RequestContext; -import org.springframework.webflow.expression.DefaultExpressionParserFactory; +import org.springframework.webflow.expression.spel.WebFlowSpringELExpressionParser; import org.springframework.webflow.test.MockFlowExecutionKey; import org.springframework.webflow.test.MockRequestContext; import org.springframework.webflow.test.MockRequestControlContext; @@ -64,7 +68,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.setExpressionParser(DefaultExpressionParserFactory.getExpressionParser()); + view.setExpressionParser(createExpressionParser()); view.render(); assertTrue(renderCalled); assertEquals("bar", model.get("foo")); @@ -94,7 +98,7 @@ public class MvcViewTests extends TestCase { context.getMockExternalContext().setNativeResponse(new MockHttpServletResponse()); org.springframework.web.servlet.View mvcView = new MockView(); AbstractMvcView view = new MockMvcView(mvcView, context); - view.setExpressionParser(DefaultExpressionParserFactory.getExpressionParser()); + view.setExpressionParser(createExpressionParser()); view.render(); assertTrue(renderCalled); assertEquals("bar", model.get("foo")); @@ -122,7 +126,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.setExpressionParser(DefaultExpressionParserFactory.getExpressionParser()); + view.setExpressionParser(createExpressionParser()); view.setConversionService(new DefaultConversionService()); view.render(); assertEquals(context.getFlowScope().get("bindBean"), model.get("bindBean")); @@ -185,7 +189,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.setExpressionParser(DefaultExpressionParserFactory.getExpressionParser()); + view.setExpressionParser(createExpressionParser()); view.processUserEvent(); assertTrue(view.hasFlowEvent()); assertFalse(context.getFlashScope().contains(ViewActionStateHolder.KEY)); @@ -233,7 +237,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.setExpressionParser(DefaultExpressionParserFactory.getExpressionParser()); + view.setExpressionParser(createExpressionParser()); view.setMessageCodesResolver(new WebFlowMessageCodesResolver()); context.setAlwaysRedirectOnPause(true); view.processUserEvent(); @@ -282,7 +286,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.setExpressionParser(DefaultExpressionParserFactory.getExpressionParser()); + view.setExpressionParser(createExpressionParser()); view.processUserEvent(); assertTrue(view.hasFlowEvent()); assertFalse(context.getFlashScope().contains(ViewActionStateHolder.KEY)); @@ -305,7 +309,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.setExpressionParser(DefaultExpressionParserFactory.getExpressionParser()); + view.setExpressionParser(createExpressionParser()); view.setMessageCodesResolver(new WebFlowMessageCodesResolver()); context.setAlwaysRedirectOnPause(true); assertTrue(view.userEventQueued()); @@ -328,7 +332,7 @@ public class MvcViewTests extends TestCase { context2.getMockExternalContext().setNativeResponse(new MockHttpServletResponse()); context2.getMockFlowExecutionContext().setKey(new MockFlowExecutionKey("c1v1")); AbstractMvcView view2 = new MockMvcView(mvcView, context2); - view2.setExpressionParser(DefaultExpressionParserFactory.getExpressionParser()); + view2.setExpressionParser(createExpressionParser()); view2.setMessageCodesResolver(new WebFlowMessageCodesResolver()); view2.restoreState((ViewActionStateHolder) viewActionState); assertFalse(view2.userEventQueued()); @@ -356,7 +360,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.setExpressionParser(DefaultExpressionParserFactory.getExpressionParser()); + view.setExpressionParser(createExpressionParser()); view.setMessageCodesResolver(new WebFlowMessageCodesResolver()); context.setAlwaysRedirectOnPause(true); assertTrue(view.userEventQueued()); @@ -381,7 +385,7 @@ public class MvcViewTests extends TestCase { context2.getMockExternalContext().setNativeResponse(new MockHttpServletResponse()); context2.getMockFlowExecutionContext().setKey(new MockFlowExecutionKey("c1v1")); AbstractMvcView view2 = new MockMvcView(mvcView, context2); - view2.setExpressionParser(DefaultExpressionParserFactory.getExpressionParser()); + view2.setExpressionParser(createExpressionParser()); view2.setMessageCodesResolver(new WebFlowMessageCodesResolver()); view2.restoreState((ViewActionStateHolder) viewActionState); assertFalse(view2.userEventQueued()); @@ -431,7 +435,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.setExpressionParser(DefaultExpressionParserFactory.getExpressionParser()); + view.setExpressionParser(createExpressionParser()); BinderConfiguration binderConfiguration = new BinderConfiguration(); binderConfiguration.addBinding(new Binding("stringProperty", null, true)); view.setBinderConfiguration(binderConfiguration); @@ -462,7 +466,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.setExpressionParser(DefaultExpressionParserFactory.getExpressionParser()); + view.setExpressionParser(createExpressionParser()); DefaultConversionService conversionService = new DefaultConversionService(); StringToDate stringToDate = new StringToDate(); stringToDate.setPattern("MM-dd-yyyy"); @@ -496,7 +500,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.setExpressionParser(DefaultExpressionParserFactory.getExpressionParser()); + view.setExpressionParser(createExpressionParser()); view.processUserEvent(); assertEquals(false, bindBean.getBooleanProperty()); } @@ -517,7 +521,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.setExpressionParser(DefaultExpressionParserFactory.getExpressionParser()); + view.setExpressionParser(createExpressionParser()); assertTrue(view.userEventQueued()); view.processUserEvent(); assertFalse(view.userEventQueued()); @@ -541,7 +545,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.setExpressionParser(DefaultExpressionParserFactory.getExpressionParser()); + view.setExpressionParser(createExpressionParser()); assertTrue(view.userEventQueued()); view.processUserEvent(); assertFalse(view.userEventQueued()); @@ -567,7 +571,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.setExpressionParser(DefaultExpressionParserFactory.getExpressionParser()); + view.setExpressionParser(createExpressionParser()); assertTrue(view.userEventQueued()); view.processUserEvent(); assertFalse(view.userEventQueued()); @@ -593,7 +597,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.setExpressionParser(DefaultExpressionParserFactory.getExpressionParser()); + view.setExpressionParser(createExpressionParser()); view.setMessageCodesResolver(new WebFlowMessageCodesResolver()); view.processUserEvent(); assertFalse(view.hasFlowEvent()); @@ -618,13 +622,21 @@ 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.setExpressionParser(DefaultExpressionParserFactory.getExpressionParser()); + view.setExpressionParser(createExpressionParser()); view.setMessageCodesResolver(new WebFlowMessageCodesResolver()); view.processUserEvent(); assertFalse(view.hasFlowEvent()); assertFalse(bindBean.validationMethodInvoked); } + private SpringELExpressionParser createExpressionParser() { + SpringELExpressionParser expressionParser = new WebFlowSpringELExpressionParser(new SpelExpressionParser()); + FormattingConversionService conversionService = (FormattingConversionService) expressionParser + .getConversionService(); + conversionService.addFormatterForFieldType(Date.class, new DateFormatter("yyyy-MM-dd")); + return expressionParser; + } + private class MockMvcView extends AbstractMvcView { public MockMvcView(View view, RequestContext context) {