From c257afa515259cbe1756fe418907f45755e92c80 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Mon, 19 Sep 2011 21:32:45 +0000 Subject: [PATCH] SPR-7943 Add interface for HDIV integration and delegate to it from JSP form tags. --- .../web/servlet/support/RequestContext.java | 29 +++++++- .../support/RequestDataValueProcessor.java | 74 +++++++++++++++++++ .../web/servlet/tags/UrlTag.java | 10 +++ .../tags/form/AbstractCheckedElementTag.java | 11 ++- .../form/AbstractDataBoundFormElementTag.java | 16 ++++ .../form/AbstractMultiCheckedElementTag.java | 6 -- .../web/servlet/tags/form/CheckboxTag.java | 12 ++- .../web/servlet/tags/form/CheckboxesTag.java | 5 +- .../web/servlet/tags/form/FormTag.java | 40 +++++++++- .../web/servlet/tags/form/HiddenInputTag.java | 5 +- .../web/servlet/tags/form/InputTag.java | 7 +- .../web/servlet/tags/form/OptionTag.java | 5 ++ .../web/servlet/tags/form/OptionWriter.java | 16 ++++ .../web/servlet/tags/form/OptionsTag.java | 23 ++++-- .../servlet/tags/form/PasswordInputTag.java | 2 +- .../web/servlet/tags/form/RadioButtonTag.java | 7 +- .../web/servlet/tags/form/SelectTag.java | 15 +++- .../web/servlet/tags/form/TextareaTag.java | 3 +- .../web/servlet/view/RedirectView.java | 18 +++++ .../servlet/tags/form/OptionTagEnumTests.java | 14 +++- .../web/servlet/tags/form/OptionTagTests.java | 61 ++++++++++----- .../servlet/tags/form/OptionsTagTests.java | 7 +- .../view/RedirectViewUriTemplateTests.java | 34 ++++----- .../view/velocity/VelocityViewTests.java | 5 ++ 24 files changed, 355 insertions(+), 70 deletions(-) create mode 100644 org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/support/RequestDataValueProcessor.java diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/support/RequestContext.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/support/RequestContext.java index 8b8f3762526..68267acf20a 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/support/RequestContext.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/support/RequestContext.java @@ -20,12 +20,14 @@ import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; + import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import javax.servlet.jsp.jstl.core.Config; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.context.MessageSource; import org.springframework.context.MessageSourceResolvable; import org.springframework.context.NoSuchMessageException; @@ -80,6 +82,12 @@ public class RequestContext { */ public static final String WEB_APPLICATION_CONTEXT_ATTRIBUTE = RequestContext.class.getName() + ".CONTEXT"; + /** + * The name of the bean to use to look up in an implementation of + * {@link RequestDataValueProcessor} has been configured. + */ + private static final String REQUEST_DATA_VALUE_PROCESSOR_BEAN_NAME = "requestDataValueProcessor"; + protected static final boolean jstlPresent = ClassUtils.isPresent("javax.servlet.jsp.jstl.core.Config", RequestContext.class.getClassLoader()); @@ -99,6 +107,8 @@ public class RequestContext { private UrlPathHelper urlPathHelper; + private RequestDataValueProcessor requestDataValueProcessor; + private Map errorsMap; /** @@ -212,8 +222,16 @@ public class RequestContext { this.defaultHtmlEscape = WebUtils.getDefaultHtmlEscape(this.webApplicationContext.getServletContext()); this.urlPathHelper = new UrlPathHelper(); - } + try { + this.requestDataValueProcessor = this.webApplicationContext.getBean( + REQUEST_DATA_VALUE_PROCESSOR_BEAN_NAME, RequestDataValueProcessor.class); + } + catch (NoSuchBeanDefinitionException ex) { + // Ignored + } + } + /** * Determine the fallback locale for this context.

The default implementation checks for a JSTL locale attribute * in request, session or application scope; if not found, returns the HttpServletRequest.getLocale(). @@ -347,6 +365,15 @@ public class RequestContext { return this.urlPathHelper; } + /** + * Return the RequestDataValueProcessor instance to use obtained from the + * WebApplicationContext under the name {@code "requestDataValueProcessor"}. + * Or {@code null} if no matching bean was found. + */ + public RequestDataValueProcessor getRequestDataValueProcessor() { + return this.requestDataValueProcessor; + } + /** * Return the context path of the original request, that is, the path that indicates the current web application. * This is useful for building links to other resources within the application.

Delegates to the UrlPathHelper diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/support/RequestDataValueProcessor.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/support/RequestDataValueProcessor.java new file mode 100644 index 00000000000..82bd0398f5f --- /dev/null +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/support/RequestDataValueProcessor.java @@ -0,0 +1,74 @@ +/* + * Copyright 2002-2011 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.web.servlet.support; + +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +/** + * A contract for inspecting and potentially modifying request data values such + * as URL query parameters or form field values before they are rendered by a + * view or before a redirect. + * + *

Implementations may use this contract for example as part of a solution + * to provide data integrity, confidentiality, protection against cross-site + * request forgery (CSRF), and others or for other tasks such as automatically + * adding a hidden field to all forms and URLs. + * + *

View technologies that support this contract can obtain an instance to + * delegate to via {@link RequestContext#getRequestDataValueProcessor()}. + * + * @author Rossen Stoyanchev + * @since 3.1 + */ +public interface RequestDataValueProcessor { + + /** + * Invoked when a new form action is rendered. + * @param request the current request + * @param action the form action + * @return the action to use, possibly modified + */ + String processAction(HttpServletRequest request, String action); + + /** + * Invoked when a form field value is rendered. + * @param request the current request + * @param name the form field name + * @param value the form field value + * @param type the form field type ("text", "hidden", etc.) + * @return the form field value to use, possibly modified + */ + String processFormFieldValue(HttpServletRequest request, String name, String value, String type); + + /** + * Invoked after all form fields have been rendered. + * @param request the current request + * @return additional hidden form fields to be added, or {@code null} + */ + Map getExtraHiddenFields(HttpServletRequest request); + + /** + * Invoked when a URL is about to be rendered or redirected to. + * @param request the current request + * @param url the URL value + * @return the URL to use, possibly modified + */ + String processUrl(HttpServletRequest request, String url); + +} diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/UrlTag.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/UrlTag.java index 0c9e12ca6ff..034339c14e2 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/UrlTag.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/UrlTag.java @@ -22,12 +22,15 @@ import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; + +import javax.servlet.ServletRequest; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.jsp.JspException; import javax.servlet.jsp.PageContext; import org.springframework.util.StringUtils; +import org.springframework.web.servlet.support.RequestDataValueProcessor; import org.springframework.web.util.ExpressionEvaluationUtils; import org.springframework.web.util.HtmlUtils; import org.springframework.web.util.JavaScriptUtils; @@ -168,6 +171,13 @@ public class UrlTag extends HtmlEscapingAwareTag implements ParamAware { @Override public int doEndTag() throws JspException { String url = createUrl(); + + RequestDataValueProcessor processor = getRequestContext().getRequestDataValueProcessor(); + ServletRequest request = this.pageContext.getRequest(); + if ((processor != null) && (request instanceof HttpServletRequest)) { + url = processor.processUrl((HttpServletRequest) request, url); + } + if (this.var == null) { // print the url to the writer try { diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/AbstractCheckedElementTag.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/AbstractCheckedElementTag.java index 5eac86407fb..e644ecd79e8 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/AbstractCheckedElementTag.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/AbstractCheckedElementTag.java @@ -44,7 +44,8 @@ public abstract class AbstractCheckedElementTag extends AbstractHtmlInputElement * bound value. */ protected void renderFromValue(Object item, Object value, TagWriter tagWriter) throws JspException { - tagWriter.writeAttribute("value", convertToDisplayString(value)); + String displayValue = convertToDisplayString(value); + tagWriter.writeAttribute("value", processFieldValue(getName(), displayValue, getInputType())); if (isOptionSelected(value) || (value != item && isOptionSelected(item))) { tagWriter.writeAttribute("checked", "checked"); } @@ -64,7 +65,7 @@ public abstract class AbstractCheckedElementTag extends AbstractHtmlInputElement * true. */ protected void renderFromBoolean(Boolean boundValue, TagWriter tagWriter) throws JspException { - tagWriter.writeAttribute("value", "true"); + tagWriter.writeAttribute("value", processFieldValue(getName(), "true", getInputType())); if (boundValue) { tagWriter.writeAttribute("checked", "checked"); } @@ -87,4 +88,10 @@ public abstract class AbstractCheckedElementTag extends AbstractHtmlInputElement @Override protected abstract int writeTagContent(TagWriter tagWriter) throws JspException; + /** + * Return the type of the HTML input element to generate: + * "checkbox" or "radio". + */ + protected abstract String getInputType(); + } diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/AbstractDataBoundFormElementTag.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/AbstractDataBoundFormElementTag.java index 84645cb24d0..aaa6add7ede 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/AbstractDataBoundFormElementTag.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/AbstractDataBoundFormElementTag.java @@ -17,6 +17,9 @@ package org.springframework.web.servlet.tags.form; import java.beans.PropertyEditor; + +import javax.servlet.ServletRequest; +import javax.servlet.http.HttpServletRequest; import javax.servlet.jsp.JspException; import javax.servlet.jsp.PageContext; @@ -24,6 +27,7 @@ import org.springframework.beans.PropertyAccessor; import org.springframework.core.Conventions; import org.springframework.util.StringUtils; import org.springframework.web.servlet.support.BindStatus; +import org.springframework.web.servlet.support.RequestDataValueProcessor; import org.springframework.web.servlet.tags.EditorAwareTag; import org.springframework.web.servlet.tags.NestedPathTag; @@ -227,6 +231,18 @@ public abstract class AbstractDataBoundFormElementTag extends AbstractFormTag im return getDisplayString(value, editor); } + /** + * Process the given form field through a {@link RequestDataValueProcessor} + * instance if one is configured or otherwise returns the same value. + */ + protected final String processFieldValue(String name, String value, String type) { + RequestDataValueProcessor processor = getRequestContext().getRequestDataValueProcessor(); + ServletRequest request = this.pageContext.getRequest(); + if (processor != null && (request instanceof HttpServletRequest)) { + value = processor.processFormFieldValue((HttpServletRequest) request, name, value, type); + } + return value; + } /** * Disposes of the {@link BindStatus} instance. diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/AbstractMultiCheckedElementTag.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/AbstractMultiCheckedElementTag.java index 5cb997346bf..6cf8af15712 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/AbstractMultiCheckedElementTag.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/AbstractMultiCheckedElementTag.java @@ -291,10 +291,4 @@ public abstract class AbstractMultiCheckedElementTag extends AbstractCheckedElem tagWriter.endTag(); } - /** - * Return the type of the HTML input element to generate: - * "checkbox" or "radio". - */ - protected abstract String getInputType(); - } diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/CheckboxTag.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/CheckboxTag.java index a809ae8557b..cd4ff0e5150 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/CheckboxTag.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/CheckboxTag.java @@ -55,8 +55,9 @@ public class CheckboxTag extends AbstractSingleCheckedElementTag { // Write out the 'field was present' marker. tagWriter.startTag("input"); tagWriter.writeAttribute("type", "hidden"); - tagWriter.writeAttribute("name", WebDataBinder.DEFAULT_FIELD_MARKER_PREFIX + getName()); - tagWriter.writeAttribute("value", "on"); + String name = WebDataBinder.DEFAULT_FIELD_MARKER_PREFIX + getName(); + tagWriter.writeAttribute("name", name); + tagWriter.writeAttribute("value", processFieldValue(name, "on", getInputType())); tagWriter.endTag(); } @@ -65,7 +66,7 @@ public class CheckboxTag extends AbstractSingleCheckedElementTag { @Override protected void writeTagDetails(TagWriter tagWriter) throws JspException { - tagWriter.writeAttribute("type", "checkbox"); + tagWriter.writeAttribute("type", getInputType()); Object boundValue = getBoundValue(); Class valueType = getBindStatus().getValueType(); @@ -89,4 +90,9 @@ public class CheckboxTag extends AbstractSingleCheckedElementTag { } } + @Override + protected String getInputType() { + return "checkbox"; + } + } diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/CheckboxesTag.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/CheckboxesTag.java index 005720725be..579ab99aa54 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/CheckboxesTag.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/CheckboxesTag.java @@ -41,8 +41,9 @@ public class CheckboxesTag extends AbstractMultiCheckedElementTag { // Write out the 'field was present' marker. tagWriter.startTag("input"); tagWriter.writeAttribute("type", "hidden"); - tagWriter.writeAttribute("name", WebDataBinder.DEFAULT_FIELD_MARKER_PREFIX + getName()); - tagWriter.writeAttribute("value", "on"); + String name = WebDataBinder.DEFAULT_FIELD_MARKER_PREFIX + getName(); + tagWriter.writeAttribute("name", name); + tagWriter.writeAttribute("value", processFieldValue(name, "on", getInputType())); tagWriter.endTag(); } diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/FormTag.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/FormTag.java index 2e9cc84f212..03071403130 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/FormTag.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/FormTag.java @@ -16,7 +16,11 @@ package org.springframework.web.servlet.tags.form; +import java.util.Map; + +import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.jsp.JspException; import javax.servlet.jsp.PageContext; @@ -25,6 +29,7 @@ import org.springframework.beans.PropertyAccessor; import org.springframework.core.Conventions; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; +import org.springframework.web.servlet.support.RequestDataValueProcessor; import org.springframework.web.util.HtmlUtils; /** @@ -393,7 +398,8 @@ public class FormTag extends AbstractHtmlElementTag { protected String resolveAction() throws JspException { String action = getAction(); if (StringUtils.hasText(action)) { - return getDisplayString(evaluate(ACTION_ATTRIBUTE, action)); + action = getDisplayString(evaluate(ACTION_ATTRIBUTE, action)); + return processAction(action); } else { String requestUri = getRequestContext().getRequestUri(); @@ -406,7 +412,7 @@ public class FormTag extends AbstractHtmlElementTag { } } if (StringUtils.hasText(requestUri)) { - return requestUri; + return processAction(requestUri); } else { throw new IllegalArgumentException("Attribute 'action' is required. " + @@ -415,6 +421,18 @@ public class FormTag extends AbstractHtmlElementTag { } } + /** + * Process the action through a {@link RequestDataValueProcessor} instance + * if one is configured or otherwise returns the action unmodified. + */ + private String processAction(String action) { + RequestDataValueProcessor processor = getRequestContext().getRequestDataValueProcessor(); + ServletRequest request = this.pageContext.getRequest(); + if ((processor != null) && (request instanceof HttpServletRequest)) { + action = processor.processAction((HttpServletRequest) request, action); + } + return action; + } /** * Closes the 'form' block tag and removes the form object name @@ -422,10 +440,28 @@ public class FormTag extends AbstractHtmlElementTag { */ @Override public int doEndTag() throws JspException { + RequestDataValueProcessor processor = getRequestContext().getRequestDataValueProcessor(); + ServletRequest request = this.pageContext.getRequest(); + if ((processor != null) && (request instanceof HttpServletRequest)) { + writeHiddenFields(processor.getExtraHiddenFields((HttpServletRequest) request)); + } this.tagWriter.endTag(); return EVAL_PAGE; } + /** + * Writes the given values as hidden fields. + */ + private void writeHiddenFields(Map hiddenFields) throws JspException { + if (hiddenFields != null) { + for (String name : hiddenFields.keySet()) { + this.tagWriter.appendValue("\n"); + } + } + } + /** * Clears the stored {@link TagWriter}. */ diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/HiddenInputTag.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/HiddenInputTag.java index aa1258577a5..7b760f5017e 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/HiddenInputTag.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/HiddenInputTag.java @@ -44,9 +44,10 @@ public class HiddenInputTag extends AbstractHtmlElementTag { tagWriter.startTag("input"); writeDefaultAttributes(tagWriter); tagWriter.writeAttribute("type", "hidden"); - tagWriter.writeAttribute("value", getDisplayString(getBoundValue(), getPropertyEditor())); + String value = getDisplayString(getBoundValue(), getPropertyEditor()); + tagWriter.writeAttribute("value", processFieldValue(getName(), value, "hidden")); tagWriter.endTag(); return SKIP_BODY; } - + } diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/InputTag.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/InputTag.java index 92d746577c8..cdb9d1d6260 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/InputTag.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/InputTag.java @@ -16,8 +16,12 @@ package org.springframework.web.servlet.tags.form; +import javax.servlet.ServletRequest; +import javax.servlet.http.HttpServletRequest; import javax.servlet.jsp.JspException; +import org.springframework.web.servlet.support.RequestDataValueProcessor; + /** * Data-binding-aware JSP tag for rendering an HTML 'input' * element with a 'type' of 'text'. @@ -158,7 +162,8 @@ public class InputTag extends AbstractHtmlInputElementTag { * when the value is written. */ protected void writeValue(TagWriter tagWriter) throws JspException { - tagWriter.writeAttribute("value", getDisplayString(getBoundValue(), getPropertyEditor())); + String value = getDisplayString(getBoundValue(), getPropertyEditor()); + tagWriter.writeAttribute("value", processFieldValue(getName(), value, getType())); } /** diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/OptionTag.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/OptionTag.java index 6fdacfcd392..0fa3de81d97 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/OptionTag.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/OptionTag.java @@ -207,6 +207,7 @@ public class OptionTag extends AbstractHtmlElementBodyTag implements BodyTag { writeOptionalAttribute(tagWriter, "id", resolveId()); writeOptionalAttributes(tagWriter); String renderedValue = getDisplayString(value, getBindStatus().getEditor()); + renderedValue = processFieldValue(getSelectTag().getName(), renderedValue, "option"); tagWriter.writeAttribute(VALUE_ATTRIBUTE, renderedValue); if (isSelected(value)) { tagWriter.writeAttribute(SELECTED_ATTRIBUTE, SELECTED_ATTRIBUTE); @@ -238,6 +239,10 @@ public class OptionTag extends AbstractHtmlElementBodyTag implements BodyTag { private void assertUnderSelectTag() { TagUtils.assertHasAncestorOfType(this, SelectTag.class, "option", "select"); } + + private SelectTag getSelectTag() { + return (SelectTag) findAncestorWithClass(this, SelectTag.class); + } private boolean isSelected(Object resolvedValue) { return SelectedValueComparator.isSelected(getBindStatus(), resolvedValue); diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/OptionWriter.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/OptionWriter.java index 41eb9296db6..8fb4edbd5ce 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/OptionWriter.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/OptionWriter.java @@ -19,13 +19,19 @@ package org.springframework.web.servlet.tags.form; import java.beans.PropertyEditor; import java.util.Collection; import java.util.Map; + +import javax.servlet.ServletRequest; +import javax.servlet.http.HttpServletRequest; import javax.servlet.jsp.JspException; +import javax.servlet.jsp.PageContext; import org.springframework.beans.BeanWrapper; import org.springframework.beans.PropertyAccessorFactory; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.web.servlet.support.BindStatus; +import org.springframework.web.servlet.support.RequestDataValueProcessor; +import org.springframework.web.servlet.support.RequestContext; /** * Provides supporting functionality to render a list of 'option' @@ -222,6 +228,8 @@ class OptionWriter { String valueDisplayString = getDisplayString(value); String labelDisplayString = getDisplayString(label); + + valueDisplayString = processOptionValue(valueDisplayString); // allows render values to handle some strange browser compat issues. tagWriter.writeAttribute("value", valueDisplayString); @@ -245,6 +253,14 @@ class OptionWriter { return ValueFormatter.getDisplayString(value, editor, this.htmlEscape); } + /** + * Process the option value before it is written. + * The default implementation simply returns the same value unchanged. + */ + protected String processOptionValue(String resolvedValue) { + return resolvedValue; + } + /** * Determine whether the supplied values matched the selected value. * Delegates to {@link SelectedValueComparator#isSelected}. diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/OptionsTag.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/OptionsTag.java index c24ecf4fa64..bf145a9c9ce 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/OptionsTag.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/OptionsTag.java @@ -17,6 +17,7 @@ package org.springframework.web.servlet.tags.form; import javax.servlet.jsp.JspException; +import javax.servlet.jsp.tagext.TagSupport; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; @@ -145,26 +146,26 @@ public class OptionsTag extends AbstractHtmlElementTag { @Override protected int writeTagContent(TagWriter tagWriter) throws JspException { - assertUnderSelectTag(); + SelectTag selectTag = getSelectTag(); Object items = getItems(); Object itemsObject = null; if (items != null) { itemsObject = (items instanceof String ? evaluate("items", items) : items); } else { - Class selectTagBoundType = ((SelectTag) findAncestorWithClass(this, SelectTag.class)) - .getBindStatus().getValueType(); + Class selectTagBoundType = selectTag.getBindStatus().getValueType(); if (selectTagBoundType != null && selectTagBoundType.isEnum()) { itemsObject = selectTagBoundType.getEnumConstants(); } } if (itemsObject != null) { + String selectName = selectTag.getName(); String itemValue = getItemValue(); String itemLabel = getItemLabel(); String valueProperty = (itemValue != null ? ObjectUtils.getDisplayString(evaluate("itemValue", itemValue)) : null); String labelProperty = (itemLabel != null ? ObjectUtils.getDisplayString(evaluate("itemLabel", itemLabel)) : null); - OptionsWriter optionWriter = new OptionsWriter(itemsObject, valueProperty, labelProperty); + OptionsWriter optionWriter = new OptionsWriter(selectName, itemsObject, valueProperty, labelProperty); optionWriter.writeOptions(tagWriter); } return SKIP_BODY; @@ -184,8 +185,9 @@ public class OptionsTag extends AbstractHtmlElementTag { return null; } - private void assertUnderSelectTag() { + private SelectTag getSelectTag() { TagUtils.assertHasAncestorOfType(this, SelectTag.class, "options", "select"); + return (SelectTag) findAncestorWithClass(this, SelectTag.class); } @Override @@ -198,9 +200,12 @@ public class OptionsTag extends AbstractHtmlElementTag { * Inner class that adapts OptionWriter for multiple options to be rendered. */ private class OptionsWriter extends OptionWriter { + + private final String selectName; - public OptionsWriter(Object optionSource, String valueProperty, String labelProperty) { + public OptionsWriter(String selectName, Object optionSource, String valueProperty, String labelProperty) { super(optionSource, getBindStatus(), valueProperty, labelProperty, isHtmlEscape()); + this.selectName = selectName; } @Override @@ -213,6 +218,12 @@ public class OptionsTag extends AbstractHtmlElementTag { writeOptionalAttribute(tagWriter, "id", resolveId()); writeOptionalAttributes(tagWriter); } + + @Override + protected String processOptionValue(String value) { + return processFieldValue(this.selectName, value, "option"); + } + } } diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/PasswordInputTag.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/PasswordInputTag.java index 1635b360141..08d9f441867 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/PasswordInputTag.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/PasswordInputTag.java @@ -66,7 +66,7 @@ public class PasswordInputTag extends InputTag { if (this.showPassword) { super.writeValue(tagWriter); } else { - tagWriter.writeAttribute("value", ""); + tagWriter.writeAttribute("value", processFieldValue(getName(), "", getType())); } } } diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/RadioButtonTag.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/RadioButtonTag.java index 32a80cabe2c..e2014ed7146 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/RadioButtonTag.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/RadioButtonTag.java @@ -36,9 +36,14 @@ public class RadioButtonTag extends AbstractSingleCheckedElementTag { @Override protected void writeTagDetails(TagWriter tagWriter) throws JspException { - tagWriter.writeAttribute("type", "radio"); + tagWriter.writeAttribute("type", getInputType()); Object resolvedValue = evaluate("value", getValue()); renderFromValue(resolvedValue, tagWriter); } + @Override + protected String getInputType() { + return "radio"; + } + } diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/SelectTag.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/SelectTag.java index 92ca364d064..aab847886da 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/SelectTag.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/SelectTag.java @@ -18,6 +18,7 @@ package org.springframework.web.servlet.tags.form; import java.util.Collection; import java.util.Map; + import javax.servlet.jsp.JspException; import org.springframework.util.ObjectUtils; @@ -207,12 +208,17 @@ public class SelectTag extends AbstractHtmlInputElementTag { if (items != EMPTY) { Object itemsObject = evaluate("items", items); if (itemsObject != null) { + final String selectName = getName(); String valueProperty = (getItemValue() != null ? ObjectUtils.getDisplayString(evaluate("itemValue", getItemValue())) : null); String labelProperty = (getItemLabel() != null ? ObjectUtils.getDisplayString(evaluate("itemLabel", getItemLabel())) : null); OptionWriter optionWriter = - new OptionWriter(itemsObject, getBindStatus(), valueProperty, labelProperty, isHtmlEscape()); + new OptionWriter(itemsObject, getBindStatus(), valueProperty, labelProperty, isHtmlEscape()) { + protected String processOptionValue(String resolvedValue) { + return processFieldValue(selectName, resolvedValue, "option"); + } + }; optionWriter.writeOptions(tagWriter); } } @@ -238,8 +244,9 @@ public class SelectTag extends AbstractHtmlInputElementTag { if (isMultiple()) { tagWriter.startTag("input"); tagWriter.writeAttribute("type", "hidden"); - tagWriter.writeAttribute("name", WebDataBinder.DEFAULT_FIELD_MARKER_PREFIX + getName()); - tagWriter.writeAttribute("value", "1"); + String name = WebDataBinder.DEFAULT_FIELD_MARKER_PREFIX + getName(); + tagWriter.writeAttribute("name", name); + tagWriter.writeAttribute("value", processFieldValue(name, "1", "hidden")); tagWriter.endTag(); } } @@ -305,5 +312,5 @@ public class SelectTag extends AbstractHtmlInputElementTag { this.tagWriter = null; this.pageContext.removeAttribute(LIST_VALUE_PAGE_ATTRIBUTE); } - + } diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/TextareaTag.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/TextareaTag.java index 048ab4287a9..c0a6fa1ba29 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/TextareaTag.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/form/TextareaTag.java @@ -96,7 +96,8 @@ public class TextareaTag extends AbstractHtmlInputElementTag { writeOptionalAttribute(tagWriter, ROWS_ATTRIBUTE, getRows()); writeOptionalAttribute(tagWriter, COLS_ATTRIBUTE, getCols()); writeOptionalAttribute(tagWriter, ONSELECT_ATTRIBUTE, getOnselect()); - tagWriter.appendValue(getDisplayString(getBoundValue(), getPropertyEditor())); + String value = getDisplayString(getBoundValue(), getPropertyEditor()); + tagWriter.appendValue(processFieldValue(getName(), value, "textarea")); tagWriter.endTag(); return SKIP_BODY; } diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/view/RedirectView.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/view/RedirectView.java index dffa139b668..87aba51ea00 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/view/RedirectView.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/view/RedirectView.java @@ -42,7 +42,9 @@ import org.springframework.web.servlet.FlashMap; import org.springframework.web.servlet.HandlerMapping; import org.springframework.web.servlet.SmartView; import org.springframework.web.servlet.View; +import org.springframework.web.servlet.support.RequestContext; import org.springframework.web.servlet.support.RequestContextUtils; +import org.springframework.web.servlet.support.RequestDataValueProcessor; import org.springframework.web.util.UriComponents; import org.springframework.web.util.UriComponentsBuilder; import org.springframework.web.util.UriUtils; @@ -228,6 +230,14 @@ public class RedirectView extends AbstractUrlBasedView implements SmartView { return true; } + /** + * An ApplicationContext is not strictly required for RedirectView. + */ + @Override + protected boolean isContextRequired() { + return false; + } + /** * Convert model to request parameters and redirect to the given URL. * @see #appendQueryProperties @@ -240,6 +250,14 @@ public class RedirectView extends AbstractUrlBasedView implements SmartView { String targetUrl = createTargetUrl(model, request); + if (getWebApplicationContext() != null) { + RequestContext requestContext = createRequestContext(request, response, model); + RequestDataValueProcessor processor = requestContext.getRequestDataValueProcessor(); + if (processor != null) { + targetUrl = processor.processUrl(request, targetUrl); + } + } + FlashMap flashMap = RequestContextUtils.getOutputFlashMap(request); if (!CollectionUtils.isEmpty(flashMap)) { UriComponents uriComponents = UriComponentsBuilder.fromUriString(targetUrl).build(); diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/tags/form/OptionTagEnumTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/tags/form/OptionTagEnumTests.java index 208f63b4baa..56aef73a1d1 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/tags/form/OptionTagEnumTests.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/tags/form/OptionTagEnumTests.java @@ -29,6 +29,8 @@ import org.springframework.web.servlet.support.BindStatus; public class OptionTagEnumTests extends AbstractHtmlElementTagTests { private OptionTag tag; + + private SelectTag parentTag; protected void onSetUp() { this.tag = new OptionTag() { @@ -36,7 +38,14 @@ public class OptionTagEnumTests extends AbstractHtmlElementTagTests { return new TagWriter(getWriter()); } }; - this.tag.setParent(new SelectTag()); + this.parentTag = new SelectTag() { + public String getName() { + // Should not be used other than to delegate to + // RequestDataValueDataProcessor + return "testName"; + } + }; + this.tag.setParent(this.parentTag); this.tag.setPageContext(getPageContext()); } @@ -44,7 +53,8 @@ public class OptionTagEnumTests extends AbstractHtmlElementTagTests { GenericBean testBean = new GenericBean(); testBean.setCustomEnum(CustomEnum.VALUE_1); getPageContext().getRequest().setAttribute("testBean", testBean); - getPageContext().setAttribute(SelectTag.LIST_VALUE_PAGE_ATTRIBUTE, new BindStatus(getRequestContext(), "testBean.customEnum", false)); + String selectName = "testBean.customEnum"; + getPageContext().setAttribute(SelectTag.LIST_VALUE_PAGE_ATTRIBUTE, new BindStatus(getRequestContext(), selectName, false)); this.tag.setValue("VALUE_1"); diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/tags/form/OptionTagTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/tags/form/OptionTagTests.java index ca062f45bcc..7263adacaa5 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/tags/form/OptionTagTests.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/tags/form/OptionTagTests.java @@ -49,6 +49,7 @@ public class OptionTagTests extends AbstractHtmlElementTagTests { private OptionTag tag; + private SelectTag parentTag; protected void onSetUp() { this.tag = new OptionTag() { @@ -56,13 +57,21 @@ public class OptionTagTests extends AbstractHtmlElementTagTests { return new TagWriter(getWriter()); } }; - this.tag.setParent(new SelectTag()); + this.parentTag = new SelectTag() { + public String getName() { + // Should not be used other than to delegate to + // RequestDataValueDataProcessor + return "testName"; + } + }; + this.tag.setParent(this.parentTag); this.tag.setPageContext(getPageContext()); } public void testCanBeDisabledEvenWhenSelected() throws Exception { - getPageContext().setAttribute(SelectTag.LIST_VALUE_PAGE_ATTRIBUTE, new BindStatus(getRequestContext(), "testBean.name", false)); + String selectName = "testBean.name"; + getPageContext().setAttribute(SelectTag.LIST_VALUE_PAGE_ATTRIBUTE, new BindStatus(getRequestContext(), selectName, false)); this.tag.setValue("bar"); this.tag.setLabel("Bar"); this.tag.setDisabled("true"); @@ -81,7 +90,8 @@ public class OptionTagTests extends AbstractHtmlElementTagTests { } public void testRenderNotSelected() throws Exception { - getPageContext().setAttribute(SelectTag.LIST_VALUE_PAGE_ATTRIBUTE, new BindStatus(getRequestContext(), "testBean.name", false)); + String selectName = "testBean.name"; + getPageContext().setAttribute(SelectTag.LIST_VALUE_PAGE_ATTRIBUTE, new BindStatus(getRequestContext(), selectName, false)); this.tag.setValue("bar"); this.tag.setLabel("Bar"); int result = this.tag.doStartTag(); @@ -101,7 +111,8 @@ public class OptionTagTests extends AbstractHtmlElementTagTests { String dynamicAttribute1 = "attr1"; String dynamicAttribute2 = "attr2"; - getPageContext().setAttribute(SelectTag.LIST_VALUE_PAGE_ATTRIBUTE, new BindStatus(getRequestContext(), "testBean.name", false)); + String selectName = "testBean.name"; + getPageContext().setAttribute(SelectTag.LIST_VALUE_PAGE_ATTRIBUTE, new BindStatus(getRequestContext(), selectName, false)); this.tag.setValue("bar"); this.tag.setLabel("Bar"); this.tag.setDynamicAttribute(null, dynamicAttribute1, dynamicAttribute1); @@ -123,7 +134,8 @@ public class OptionTagTests extends AbstractHtmlElementTagTests { } public void testRenderSelected() throws Exception { - getPageContext().setAttribute(SelectTag.LIST_VALUE_PAGE_ATTRIBUTE, new BindStatus(getRequestContext(), "testBean.name", false)); + String selectName = "testBean.name"; + getPageContext().setAttribute(SelectTag.LIST_VALUE_PAGE_ATTRIBUTE, new BindStatus(getRequestContext(), selectName, false)); this.tag.setId("myOption"); this.tag.setValue("foo"); this.tag.setLabel("Foo"); @@ -143,7 +155,8 @@ public class OptionTagTests extends AbstractHtmlElementTagTests { } public void testWithNoLabel() throws Exception { - getPageContext().setAttribute(SelectTag.LIST_VALUE_PAGE_ATTRIBUTE, new BindStatus(getRequestContext(), "testBean.name", false)); + String selectName = "testBean.name"; + getPageContext().setAttribute(SelectTag.LIST_VALUE_PAGE_ATTRIBUTE, new BindStatus(getRequestContext(), selectName, false)); this.tag.setValue("bar"); this.tag.setCssClass("myClass"); this.tag.setOnclick("CLICK"); @@ -175,7 +188,8 @@ public class OptionTagTests extends AbstractHtmlElementTagTests { } public void testWithEnum() throws Exception { - getPageContext().setAttribute(SelectTag.LIST_VALUE_PAGE_ATTRIBUTE, new BindStatus(getRequestContext(), "testBean.favouriteColour", false)); + String selectName = "testBean.favouriteColour"; + getPageContext().setAttribute(SelectTag.LIST_VALUE_PAGE_ATTRIBUTE, new BindStatus(getRequestContext(), selectName, false)); String value = Colour.GREEN.getCode().toString(); String label = Colour.GREEN.getLabel(); @@ -198,7 +212,8 @@ public class OptionTagTests extends AbstractHtmlElementTagTests { } public void testWithEnumNotSelected() throws Exception { - getPageContext().setAttribute(SelectTag.LIST_VALUE_PAGE_ATTRIBUTE, new BindStatus(getRequestContext(), "testBean.favouriteColour", false)); + String selectName = "testBean.favouriteColour"; + getPageContext().setAttribute(SelectTag.LIST_VALUE_PAGE_ATTRIBUTE, new BindStatus(getRequestContext(), selectName, false)); String value = Colour.BLUE.getCode().toString(); String label = Colour.BLUE.getLabel(); @@ -221,7 +236,8 @@ public class OptionTagTests extends AbstractHtmlElementTagTests { } public void testWithPropertyEditor() throws Exception { - BindStatus bindStatus = new BindStatus(getRequestContext(), "testBean.stringArray", false) { + String selectName = "testBean.stringArray"; + BindStatus bindStatus = new BindStatus(getRequestContext(), selectName, false) { public PropertyEditor getEditor() { return new StringArrayPropertyEditor(); } @@ -249,7 +265,8 @@ public class OptionTagTests extends AbstractHtmlElementTagTests { public void testWithPropertyEditorStringComparison() throws Exception { final PropertyEditor testBeanEditor = new TestBeanPropertyEditor(); testBeanEditor.setValue(new TestBean("Sally")); - BindStatus bindStatus = new BindStatus(getRequestContext(), "testBean.spouse", false) { + String selectName = "testBean.spouse"; + BindStatus bindStatus = new BindStatus(getRequestContext(), selectName, false) { public PropertyEditor getEditor() { return testBeanEditor; } @@ -272,7 +289,8 @@ public class OptionTagTests extends AbstractHtmlElementTagTests { } public void testWithCustomObjectSelected() throws Exception { - getPageContext().setAttribute(SelectTag.LIST_VALUE_PAGE_ATTRIBUTE, new BindStatus(getRequestContext(), "testBean.someNumber", false)); + String selectName = "testBean.someNumber"; + getPageContext().setAttribute(SelectTag.LIST_VALUE_PAGE_ATTRIBUTE, new BindStatus(getRequestContext(), selectName, false)); this.tag.setValue("${myNumber}"); this.tag.setLabel("GBP ${myNumber}"); int result = this.tag.doStartTag(); @@ -290,7 +308,8 @@ public class OptionTagTests extends AbstractHtmlElementTagTests { } public void testWithCustomObjectNotSelected() throws Exception { - getPageContext().setAttribute(SelectTag.LIST_VALUE_PAGE_ATTRIBUTE, new BindStatus(getRequestContext(), "testBean.someNumber", false)); + String selectName = "testBean.someNumber"; + getPageContext().setAttribute(SelectTag.LIST_VALUE_PAGE_ATTRIBUTE, new BindStatus(getRequestContext(), selectName, false)); this.tag.setValue("${myOtherNumber}"); this.tag.setLabel("GBP ${myOtherNumber}"); int result = this.tag.doStartTag(); @@ -310,7 +329,8 @@ public class OptionTagTests extends AbstractHtmlElementTagTests { public void testWithCustomObjectAndEditorSelected() throws Exception { final PropertyEditor floatEditor = new SimpleFloatEditor(); floatEditor.setValue(new Float("12.34")); - BindStatus bindStatus = new BindStatus(getRequestContext(), "testBean.someNumber", false) { + String selectName = "testBean.someNumber"; + BindStatus bindStatus = new BindStatus(getRequestContext(), selectName, false) { public PropertyEditor getEditor() { return floatEditor; } @@ -334,7 +354,8 @@ public class OptionTagTests extends AbstractHtmlElementTagTests { public void testWithCustomObjectAndEditorNotSelected() throws Exception { final PropertyEditor floatEditor = new SimpleFloatEditor(); - BindStatus bindStatus = new BindStatus(getRequestContext(), "testBean.someNumber", false) { + String selectName = "testBean.someNumber"; + BindStatus bindStatus = new BindStatus(getRequestContext(), selectName, false) { public PropertyEditor getEditor() { return floatEditor; } @@ -357,7 +378,8 @@ public class OptionTagTests extends AbstractHtmlElementTagTests { } public void testAsBodyTag() throws Exception { - BindStatus bindStatus = new BindStatus(getRequestContext(), "testBean.name", false); + String selectName = "testBean.name"; + BindStatus bindStatus = new BindStatus(getRequestContext(), selectName, false); getPageContext().setAttribute(SelectTag.LIST_VALUE_PAGE_ATTRIBUTE, bindStatus); String bodyContent = "some content"; @@ -377,7 +399,8 @@ public class OptionTagTests extends AbstractHtmlElementTagTests { } public void testAsBodyTagSelected() throws Exception { - BindStatus bindStatus = new BindStatus(getRequestContext(), "testBean.name", false); + String selectName = "testBean.name"; + BindStatus bindStatus = new BindStatus(getRequestContext(), selectName, false); getPageContext().setAttribute(SelectTag.LIST_VALUE_PAGE_ATTRIBUTE, bindStatus); String bodyContent = "some content"; @@ -396,7 +419,8 @@ public class OptionTagTests extends AbstractHtmlElementTagTests { } public void testAsBodyTagCollapsed() throws Exception { - BindStatus bindStatus = new BindStatus(getRequestContext(), "testBean.name", false); + String selectName = "testBean.name"; + BindStatus bindStatus = new BindStatus(getRequestContext(), selectName, false); getPageContext().setAttribute(SelectTag.LIST_VALUE_PAGE_ATTRIBUTE, bindStatus); String bodyContent = "some content"; @@ -416,7 +440,8 @@ public class OptionTagTests extends AbstractHtmlElementTagTests { } public void testAsBodyTagWithEditor() throws Exception { - BindStatus bindStatus = new BindStatus(getRequestContext(), "testBean.stringArray", false) { + String selectName = "testBean.stringArray"; + BindStatus bindStatus = new BindStatus(getRequestContext(), selectName, false) { public PropertyEditor getEditor() { return new RulesVariantEditor(); } diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/tags/form/OptionsTagTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/tags/form/OptionsTagTests.java index 3323bcdcd4d..bd8973b7d07 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/tags/form/OptionsTagTests.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/tags/form/OptionsTagTests.java @@ -64,6 +64,11 @@ public final class OptionsTagTests extends AbstractHtmlElementTagTests { protected TagWriter createTagWriter() { return new TagWriter(getWriter()); } + public String getName() { + // Should not be used other than to delegate to + // RequestDataValueDataProcessor + return "testName"; + } }; selectTag.setPageContext(getPageContext()); this.tag.setParent(selectTag); @@ -299,5 +304,5 @@ public final class OptionsTagTests extends AbstractHtmlElementTagTests { RequestContext context = new RequestContext((HttpServletRequest) pageContext.getRequest(), model); pageContext.setAttribute(RequestContextAwareTag.REQUEST_CONTEXT_PAGE_ATTRIBUTE, context); } - + } diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/view/RedirectViewUriTemplateTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/view/RedirectViewUriTemplateTests.java index b9dc6fd0929..b1e01024b21 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/view/RedirectViewUriTemplateTests.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/view/RedirectViewUriTemplateTests.java @@ -33,11 +33,11 @@ public class RedirectViewUriTemplateTests { private MockHttpServletRequest request; private MockHttpServletResponse response; - + @Before public void setUp() { - request = new MockHttpServletRequest(); - response = new MockHttpServletResponse(); + this.request = new MockHttpServletRequest(); + this.response = new MockHttpServletResponse(); } @Test @@ -47,9 +47,9 @@ public class RedirectViewUriTemplateTests { String baseUrl = "http://url.somewhere.com"; RedirectView redirectView = new RedirectView(baseUrl + "/{foo}"); - redirectView.renderMergedOutputModel(model, request, response); + redirectView.renderMergedOutputModel(model, this.request, this.response); - assertEquals(baseUrl + "/bar", response.getRedirectedUrl()); + assertEquals(baseUrl + "/bar", this.response.getRedirectedUrl()); } @Test @@ -59,9 +59,9 @@ public class RedirectViewUriTemplateTests { String baseUrl = "http://url.somewhere.com"; RedirectView redirectView = new RedirectView(baseUrl + "/context path/{foo}"); - redirectView.renderMergedOutputModel(model, request, response); + redirectView.renderMergedOutputModel(model, this.request, this.response); - assertEquals(baseUrl + "/context path/bar%2Fbar%20baz", response.getRedirectedUrl()); + assertEquals(baseUrl + "/context path/bar%2Fbar%20baz", this.response.getRedirectedUrl()); } @Test @@ -71,9 +71,9 @@ public class RedirectViewUriTemplateTests { model.put("fooArr", new String[] { "baz", "bazz" }); RedirectView redirectView = new RedirectView("/foo/{foo}"); - redirectView.renderMergedOutputModel(model, request, response); + redirectView.renderMergedOutputModel(model, this.request, this.response); - assertEquals("/foo/bar?fooArr=baz&fooArr=bazz", response.getRedirectedUrl()); + assertEquals("/foo/bar?fooArr=baz&fooArr=bazz", this.response.getRedirectedUrl()); } @Test @@ -82,9 +82,9 @@ public class RedirectViewUriTemplateTests { model.put("foo", new Long(611)); RedirectView redirectView = new RedirectView("/foo/{foo}"); - redirectView.renderMergedOutputModel(model, request, response); + redirectView.renderMergedOutputModel(model, this.request, this.response); - assertEquals("/foo/611", response.getRedirectedUrl()); + assertEquals("/foo/611", this.response.getRedirectedUrl()); } @Test @@ -98,18 +98,18 @@ public class RedirectViewUriTemplateTests { currentRequestUriTemplateVars.put("var1", "v1"); currentRequestUriTemplateVars.put("name", "v2"); currentRequestUriTemplateVars.put("var3", "v3"); - request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, currentRequestUriTemplateVars); + this.request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, currentRequestUriTemplateVars); String url = "http://url.somewhere.com"; RedirectView redirectView = new RedirectView(url + "/{key1}/{var1}/{name}"); - redirectView.renderMergedOutputModel(model, request, response); + redirectView.renderMergedOutputModel(model, this.request, this.response); - assertEquals(url + "/value1/v1/value2?key3=value3", response.getRedirectedUrl()); + assertEquals(url + "/value1/v1/value2?key3=value3", this.response.getRedirectedUrl()); } @Test(expected=IllegalArgumentException.class) public void uriTemplateNullValue() throws Exception { - new RedirectView("/{foo}").renderMergedOutputModel(new ModelMap(), request, response); + new RedirectView("/{foo}").renderMergedOutputModel(new ModelMap(), this.request, this.response); } @Test @@ -117,9 +117,9 @@ public class RedirectViewUriTemplateTests { Map model = new HashMap(); RedirectView redirectView = new RedirectView(""); - redirectView.renderMergedOutputModel(model, request, response); + redirectView.renderMergedOutputModel(model, this.request, this.response); - assertEquals("", response.getRedirectedUrl()); + assertEquals("", this.response.getRedirectedUrl()); } } diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/view/velocity/VelocityViewTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/view/velocity/VelocityViewTests.java index 8dd8c0a2ebe..c00b80150d6 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/view/velocity/VelocityViewTests.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/view/velocity/VelocityViewTests.java @@ -50,6 +50,7 @@ import org.springframework.web.context.WebApplicationContext; import org.springframework.web.servlet.DispatcherServlet; import org.springframework.web.servlet.View; import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver; +import org.springframework.web.servlet.support.RequestDataValueProcessor; import org.springframework.web.servlet.view.AbstractView; /** @@ -148,6 +149,8 @@ public class VelocityViewTests { expectLastCall().andReturn(null); wac.getServletContext(); expectLastCall().andReturn(sc).times(3); + wac.getBean("requestDataValueProcessor", RequestDataValueProcessor.class); + expectLastCall().andReturn(null); replay(wac); HttpServletRequest request = new MockHttpServletRequest(); @@ -203,6 +206,8 @@ public class VelocityViewTests { expectLastCall().andReturn(null); wac.getServletContext(); expectLastCall().andReturn(sc).times(3); + wac.getBean("requestDataValueProcessor", RequestDataValueProcessor.class); + expectLastCall().andReturn(null); replay(wac); HttpServletRequest request = new MockHttpServletRequest();