diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/xml/XmlFlowBuilder.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/xml/XmlFlowBuilder.java index fae12b87..d939fdfe 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/xml/XmlFlowBuilder.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/xml/XmlFlowBuilder.java @@ -192,7 +192,7 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde } public void buildInputMapper() throws FlowBuilderException { - AttributeMapper inputMapper = parseInputMapper(getDocumentElement(), AttributeMap.class, RequestContext.class); + AttributeMapper inputMapper = parseFlowInputMapper(getDocumentElement()); if (inputMapper != null) { getFlow().setInputMapper(inputMapper); } @@ -215,8 +215,7 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde } public void buildOutputMapper() throws FlowBuilderException { - AttributeMapper outputMapper = parseOutputMapper(getDocumentElement(), RequestContext.class, - MutableAttributeMap.class); + AttributeMapper outputMapper = parseFlowOutputMapper(getDocumentElement()); if (outputMapper != null) { getFlow().setOutputMapper(outputMapper); } @@ -373,32 +372,45 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde } } - private AttributeMapper parseInputMapper(Element element, Class sourceType, Class targetType) { + private AttributeMapper parseFlowInputMapper(Element element) { Collection inputs = DomUtils.getChildElementsByTagName(element, "input"); if (inputs.size() == 0) { return null; } DefaultAttributeMapper inputMapper = new DefaultAttributeMapper(); for (Iterator it = inputs.iterator(); it.hasNext();) { - parseInputMapping((Element) it.next(), inputMapper, sourceType, targetType); + inputMapper.addMapping(parseFlowInputMapping((Element) it.next())); } return inputMapper; } - private AttributeMapper parseOutputMapper(Element element, Class sourceType, Class targetType) { + private Mapping parseFlowInputMapping(Element element) { + ExpressionParser parser = getLocalContext().getExpressionParser(); + String name = element.getAttribute("name"); + String value = null; + if (element.hasAttribute("value")) { + value = element.getAttribute("value"); + } else { + value = element.getAttribute(name); + } + Expression source = parser.parseExpression(name, new ParserContextImpl().eval(MutableAttributeMap.class)); + Expression target = parser.parseExpression(value, new ParserContextImpl().eval(RequestContext.class)); + return new Mapping(source, target, parseMappingConversionExecutor(element), parseMappingRequired(element)); + } + + private AttributeMapper parseFlowOutputMapper(Element element) { Collection inputs = DomUtils.getChildElementsByTagName(element, "output"); if (inputs.size() == 0) { return null; } DefaultAttributeMapper outputMapper = new DefaultAttributeMapper(); for (Iterator it = inputs.iterator(); it.hasNext();) { - parseOutputMapping((Element) it.next(), outputMapper, sourceType, targetType); + outputMapper.addMapping(parseFlowOutputMapping((Element) it.next())); } return outputMapper; } - private Mapping parseInputMapping(Element element, DefaultAttributeMapper mapper, Class sourceClass, - Class targetClass) { + private Mapping parseFlowOutputMapping(Element element) { ExpressionParser parser = getLocalContext().getExpressionParser(); String name = element.getAttribute("name"); String value = null; @@ -407,23 +419,8 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde } else { value = element.getAttribute(name); } - Expression source = parser.parseExpression(name, new ParserContextImpl().eval(sourceClass)); - Expression target = parser.parseExpression(value, new ParserContextImpl().eval(targetClass)); - return new Mapping(source, target, parseMappingConversionExecutor(element), parseMappingRequired(element)); - } - - private Mapping parseOutputMapping(Element element, DefaultAttributeMapper mapper, Class sourceClass, - Class targetClass) { - ExpressionParser parser = getLocalContext().getExpressionParser(); - String name = element.getAttribute("name"); - String value = null; - if (element.hasAttribute("value")) { - value = element.getAttribute("value"); - } else { - value = element.getAttribute(name); - } - Expression source = parser.parseExpression(value, new ParserContextImpl().eval(sourceClass)); - Expression target = parser.parseExpression(name, new ParserContextImpl().eval(targetClass)); + Expression source = parser.parseExpression(name, new ParserContextImpl().eval(RequestContext.class)); + Expression target = parser.parseExpression(value, new ParserContextImpl().eval(MutableAttributeMap.class)); return new Mapping(source, target, parseMappingConversionExecutor(element), parseMappingRequired(element)); } @@ -557,8 +554,7 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde } parseAndSetSecuredAttribute(element, attributes); getFlowArtifactFactory().createEndState(parseId(element), flow, parseEntryActions(element), - new ViewFactoryActionAdapter(parseViewFactory(element, true)), - parseOutputMapper(element, RequestContext.class, MutableAttributeMap.class), + new ViewFactoryActionAdapter(parseViewFactory(element, true)), parseFlowOutputMapper(element), parseExceptionHandlers(element), attributes); } @@ -806,12 +802,64 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde return (SubflowAttributeMapper) getLocalContext().getBeanFactory().getBean(attributeMapperBeanId, SubflowAttributeMapper.class); } else { - AttributeMapper inputMapper = parseInputMapper(element, RequestContext.class, MutableAttributeMap.class); - AttributeMapper outputMapper = parseOutputMapper(element, AttributeMap.class, RequestContext.class); + AttributeMapper inputMapper = parseSubflowInputMapper(element); + AttributeMapper outputMapper = parseSubflowOutputMapper(element); return new GenericSubflowAttributeMapper(inputMapper, outputMapper); } } + private AttributeMapper parseSubflowInputMapper(Element element) { + Collection inputs = DomUtils.getChildElementsByTagName(element, "input"); + if (inputs.size() == 0) { + return null; + } + DefaultAttributeMapper inputMapper = new DefaultAttributeMapper(); + for (Iterator it = inputs.iterator(); it.hasNext();) { + inputMapper.addMapping(parseSubflowInputMapping((Element) it.next())); + } + return inputMapper; + } + + private Mapping parseSubflowInputMapping(Element element) { + ExpressionParser parser = getLocalContext().getExpressionParser(); + String name = element.getAttribute("name"); + String value = null; + if (element.hasAttribute("value")) { + value = element.getAttribute("value"); + } else { + value = element.getAttribute(name); + } + Expression source = parser.parseExpression(value, new ParserContextImpl().eval(RequestContext.class)); + Expression target = parser.parseExpression(name, new ParserContextImpl().eval(MutableAttributeMap.class)); + return new Mapping(source, target, parseMappingConversionExecutor(element), parseMappingRequired(element)); + } + + private AttributeMapper parseSubflowOutputMapper(Element element) { + Collection inputs = DomUtils.getChildElementsByTagName(element, "output"); + if (inputs.size() == 0) { + return null; + } + DefaultAttributeMapper outputMapper = new DefaultAttributeMapper(); + for (Iterator it = inputs.iterator(); it.hasNext();) { + outputMapper.addMapping(parseSubflowOutputMapping((Element) it.next())); + } + return outputMapper; + } + + private Mapping parseSubflowOutputMapping(Element element) { + ExpressionParser parser = getLocalContext().getExpressionParser(); + String name = element.getAttribute("name"); + String value = null; + if (element.hasAttribute("value")) { + value = element.getAttribute("value"); + } else { + value = element.getAttribute(name); + } + Expression source = parser.parseExpression(name, new ParserContextImpl().eval(MutableAttributeMap.class)); + Expression target = parser.parseExpression(value, new ParserContextImpl().eval(RequestContext.class)); + return new Mapping(source, target, parseMappingConversionExecutor(element), parseMappingRequired(element)); + } + private FlowExecutionExceptionHandler[] parseExceptionHandlers(Element element) { FlowExecutionExceptionHandler[] transitionExecutingHandlers = parseTransitionExecutingExceptionHandlers(element); FlowExecutionExceptionHandler[] customHandlers = parseCustomExceptionHandlers(element); diff --git a/spring-webflow/src/main/java/org/springframework/webflow/expression/el/WebFlowImplicitObjectELResolver.java b/spring-webflow/src/main/java/org/springframework/webflow/expression/el/ImplicitFlowVariableELResolver.java similarity index 63% rename from spring-webflow/src/main/java/org/springframework/webflow/expression/el/WebFlowImplicitObjectELResolver.java rename to spring-webflow/src/main/java/org/springframework/webflow/expression/el/ImplicitFlowVariableELResolver.java index 824faa45..d6a08cb8 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/expression/el/WebFlowImplicitObjectELResolver.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/expression/el/ImplicitFlowVariableELResolver.java @@ -12,7 +12,7 @@ import javax.el.PropertyNotWritableException; import org.springframework.webflow.execution.RequestContext; import org.springframework.webflow.execution.RequestContextHolder; -public class WebFlowImplicitObjectELResolver extends ELResolver { +public class ImplicitFlowVariableELResolver extends ELResolver { public Class getCommonPropertyType(ELContext context, Object base) { return Object.class; @@ -23,43 +23,63 @@ public class WebFlowImplicitObjectELResolver extends ELResolver { } public Class getType(ELContext context, Object base, Object property) { - if (base == null && RequestContextHolder.getRequestContext() == null && ImplicitVariable.matches(property)) { - return ImplicitVariable.value(context, RequestContextHolder.getRequestContext(), property).getClass(); + if (base != null) { + return null; + } + RequestContext requestContext = RequestContextHolder.getRequestContext(); + if (ImplicitVariables.matches(property)) { + context.setPropertyResolved(true); + return ImplicitVariables.value(context, requestContext, property).getClass(); + } else { + return null; } - return null; } public Object getValue(ELContext context, Object base, Object property) { - if (base == null && RequestContextHolder.getRequestContext() == null && ImplicitVariable.matches(property)) { - return ImplicitVariable.value(context, RequestContextHolder.getRequestContext(), property); + if (base != null) { + return null; + } + RequestContext requestContext = RequestContextHolder.getRequestContext(); + if (ImplicitVariables.matches(property)) { + context.setPropertyResolved(true); + return ImplicitVariables.value(context, requestContext, property); + } else { + return null; } - return null; } public boolean isReadOnly(ELContext context, Object base, Object property) { - if (base == null && RequestContextHolder.getRequestContext() == null && ImplicitVariable.matches(property)) { + if (base != null) { + return false; + } + if (ImplicitVariables.matches(property)) { context.setPropertyResolved(true); return true; + } else { + return false; } - return false; } public void setValue(ELContext context, Object base, Object property, Object value) { - if (base == null && RequestContextHolder.getRequestContext() == null && ImplicitVariable.matches(property)) { + if (base != null) { + return; + } + if (ImplicitVariables.matches(property)) { context.setPropertyResolved(true); throw new PropertyNotWritableException("The implicit flow variable " + property + " is not writable."); } } - private static final class ImplicitVariable { + private static final class ImplicitVariables { private static final Set vars = new HashSet(); static { + vars.add("requestParameters"); vars.add("requestScope"); vars.add("flashScope"); vars.add("flowScope"); vars.add("conversationScope"); - vars.add("requestParameters"); + vars.add("messageContext"); } private static final BeanELResolver internalResolver = new BeanELResolver(); @@ -70,6 +90,6 @@ public class WebFlowImplicitObjectELResolver extends ELResolver { public static Object value(ELContext elContext, RequestContext requestContext, Object property) { return internalResolver.getValue(elContext, requestContext, property); - }; + } } } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/expression/el/WebFlowELExpressionParser.java b/spring-webflow/src/main/java/org/springframework/webflow/expression/el/WebFlowELExpressionParser.java index 920fbf11..bd5426b0 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/expression/el/WebFlowELExpressionParser.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/expression/el/WebFlowELExpressionParser.java @@ -44,7 +44,7 @@ public class WebFlowELExpressionParser extends ELExpressionParser { public ELContext getELContext(Object target) { List customResolvers = new ArrayList(); customResolvers.add(new RequestContextELResolver()); - customResolvers.add(new WebFlowImplicitObjectELResolver()); + customResolvers.add(new ImplicitFlowVariableELResolver()); customResolvers.add(new SpringBeanWebFlowELResolver()); customResolvers.add(new ActionMethodELResolver()); customResolvers.add(new ScopeSearchingELResolver()); diff --git a/spring-webflow/src/test/java/org/springframework/webflow/test/search-flow.xml b/spring-webflow/src/test/java/org/springframework/webflow/test/search-flow.xml index 0544c993..9d524247 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/test/search-flow.xml +++ b/spring-webflow/src/test/java/org/springframework/webflow/test/search-flow.xml @@ -21,7 +21,7 @@ - +