提交 f74a631e 编写于 作者: J Juergen Hoeller

Nullability refinements in spring-webmvc

Includes revision of web.servlet.tags.form for non-null conventions.

Issue: SPR-15540
上级 4a147d26
......@@ -51,7 +51,7 @@ public class ModelMap extends LinkedHashMap<String, Object> {
* under the supplied name.
* @see #addAttribute(String, Object)
*/
public ModelMap(String attributeName, Object attributeValue) {
public ModelMap(String attributeName, @Nullable Object attributeValue) {
addAttribute(attributeName, attributeValue);
}
......
......@@ -280,12 +280,12 @@ public class ModelAndView {
/**
* Add an attribute to the model.
* @param attributeName name of the object to add to the model
* @param attributeValue object to add to the model (never {@code null})
* @param attributeName name of the object to add to the model (never {@code null})
* @param attributeValue object to add to the model (can be {@code null})
* @see ModelMap#addAttribute(String, Object)
* @see #getModelMap()
*/
public ModelAndView addObject(String attributeName, Object attributeValue) {
public ModelAndView addObject(String attributeName, @Nullable Object attributeValue) {
getModelMap().addAttribute(attributeName, attributeValue);
return this;
}
......
......@@ -51,17 +51,17 @@ public interface RequestDataValueProcessor {
/**
* Invoked when a form field value is rendered.
* @param request the current request
* @param name the form field name
* @param name the form field name (if any)
* @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);
String processFormFieldValue(HttpServletRequest request, @Nullable 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}
* @return additional hidden form fields to be added, or {@code null} if none
*/
@Nullable
Map<String, String> getExtraHiddenFields(HttpServletRequest request);
......
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2018 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.
......@@ -18,6 +18,8 @@ package org.springframework.web.servlet.tags.form;
import javax.servlet.jsp.JspException;
import org.springframework.lang.Nullable;
/**
* Abstract base class to provide common methods for
* implementing databinding-aware JSP tags for rendering an HTML '{@code input}'
......@@ -36,7 +38,7 @@ public abstract class AbstractCheckedElementTag extends AbstractHtmlInputElement
* '{@code input}' element as 'checked' if the supplied value matches the
* bound value.
*/
protected void renderFromValue(Object value, TagWriter tagWriter) throws JspException {
protected void renderFromValue(@Nullable Object value, TagWriter tagWriter) throws JspException {
renderFromValue(value, value, tagWriter);
}
......@@ -45,7 +47,9 @@ public abstract class AbstractCheckedElementTag extends AbstractHtmlInputElement
* '{@code input}' element as 'checked' if the supplied value matches the
* bound value.
*/
protected void renderFromValue(Object item, Object value, TagWriter tagWriter) throws JspException {
protected void renderFromValue(@Nullable Object item, @Nullable Object value, TagWriter tagWriter)
throws JspException {
String displayValue = convertToDisplayString(value);
tagWriter.writeAttribute("value", processFieldValue(getName(), displayValue, getInputType()));
if (isOptionSelected(value) || (value != item && isOptionSelected(item))) {
......@@ -57,7 +61,7 @@ public abstract class AbstractCheckedElementTag extends AbstractHtmlInputElement
* Determines whether the supplied value matched the selected value
* through delegating to {@link SelectedValueComparator#isSelected}.
*/
private boolean isOptionSelected(Object value) throws JspException {
private boolean isOptionSelected(@Nullable Object value) throws JspException {
return SelectedValueComparator.isSelected(getBindStatus(), value);
}
......@@ -77,8 +81,10 @@ public abstract class AbstractCheckedElementTag extends AbstractHtmlInputElement
* Return a unique ID for the bound name within the current PageContext.
*/
@Override
@Nullable
protected String autogenerateId() throws JspException {
return TagIdGenerator.nextId(super.autogenerateId(), this.pageContext);
String id = super.autogenerateId();
return (id != null ? TagIdGenerator.nextId(id, this.pageContext) : null);
}
......
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 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.
......@@ -55,16 +55,19 @@ public abstract class AbstractDataBoundFormElementTag extends AbstractFormTag im
/**
* The property path from the {@link FormTag#setModelAttribute form object}.
*/
@Nullable
private String path;
/**
* The value of the '{@code id}' attribute.
*/
@Nullable
private String id;
/**
* The {@link BindStatus} of this tag.
*/
@Nullable
private BindStatus bindStatus;
......@@ -91,7 +94,7 @@ public abstract class AbstractDataBoundFormElementTag extends AbstractFormTag im
* Note that the default value may not be valid for certain tags.
*/
@Override
public void setId(String id) {
public void setId(@Nullable String id) {
this.id = id;
}
......@@ -99,6 +102,7 @@ public abstract class AbstractDataBoundFormElementTag extends AbstractFormTag im
* Get the value of the '{@code id}' attribute.
*/
@Override
@Nullable
public String getId() {
return this.id;
}
......@@ -179,6 +183,7 @@ public abstract class AbstractDataBoundFormElementTag extends AbstractFormTag im
* Get the value of the nested path that may have been exposed by the
* {@link NestedPathTag}.
*/
@Nullable
protected String getNestedPath() {
return (String) this.pageContext.getAttribute(NESTED_PATH_VARIABLE_NAME, PageContext.REQUEST_SCOPE);
}
......@@ -225,7 +230,7 @@ public abstract class AbstractDataBoundFormElementTag extends AbstractFormTag im
* Get a display String for the given value, converted by a PropertyEditor
* that the BindStatus may have registered for the value's Class.
*/
protected String convertToDisplayString(Object value) throws JspException {
protected String convertToDisplayString(@Nullable Object value) throws JspException {
PropertyEditor editor = (value != null ? getBindStatus().findEditor(value.getClass()) : null);
return getDisplayString(value, editor);
}
......@@ -234,10 +239,10 @@ public abstract class AbstractDataBoundFormElementTag extends AbstractFormTag im
* 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) {
protected final String processFieldValue(@Nullable String name, String value, String type) {
RequestDataValueProcessor processor = getRequestContext().getRequestDataValueProcessor();
ServletRequest request = this.pageContext.getRequest();
if (processor != null && (request instanceof HttpServletRequest)) {
if (processor != null && request instanceof HttpServletRequest) {
value = processor.processFormFieldValue((HttpServletRequest) request, name, value, type);
}
return value;
......
......@@ -45,7 +45,8 @@ public abstract class AbstractFormTag extends HtmlEscapingAwareTag {
* Evaluate the supplied value for the supplied attribute name.
* <p>The default implementation simply returns the given value as-is.
*/
protected Object evaluate(String attributeName, Object value) throws JspException {
@Nullable
protected Object evaluate(String attributeName, @Nullable Object value) throws JspException {
return value;
}
......@@ -89,7 +90,7 @@ public abstract class AbstractFormTag extends HtmlEscapingAwareTag {
* Get the display value of the supplied {@code Object}, HTML escaped
* as required. This version is <strong>not</strong> {@link PropertyEditor}-aware.
*/
protected String getDisplayString(Object value) {
protected String getDisplayString(@Nullable Object value) {
return ValueFormatter.getDisplayString(value, isHtmlEscape());
}
......@@ -99,7 +100,7 @@ public abstract class AbstractFormTag extends HtmlEscapingAwareTag {
* {@link PropertyEditor} is not null then the {@link PropertyEditor} is used
* to obtain the display value.
*/
protected String getDisplayString(Object value, PropertyEditor propertyEditor) {
protected String getDisplayString(@Nullable Object value, @Nullable PropertyEditor propertyEditor) {
return ValueFormatter.getDisplayString(value, propertyEditor, isHtmlEscape());
}
......
......@@ -21,6 +21,8 @@ import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyContent;
import javax.servlet.jsp.tagext.BodyTag;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
......@@ -35,8 +37,10 @@ import org.springframework.util.StringUtils;
@SuppressWarnings("serial")
public abstract class AbstractHtmlElementBodyTag extends AbstractHtmlElementTag implements BodyTag {
@Nullable
private BodyContent bodyContent;
@Nullable
private TagWriter tagWriter;
......@@ -57,11 +61,12 @@ public abstract class AbstractHtmlElementBodyTag extends AbstractHtmlElementTag
* If {@link #shouldRender rendering}, flush any buffered
* {@link BodyContent} or, if no {@link BodyContent} is supplied,
* {@link #renderDefaultContent render the default content}.
* @return a {@link Tag#EVAL_PAGE} result
* @return a {@link javax.servlet.jsp.tagext.Tag#EVAL_PAGE} result
*/
@Override
public int doEndTag() throws JspException {
if (shouldRender()) {
Assert.state(this.tagWriter != null, "No TagWriter set");
if (this.bodyContent != null && StringUtils.hasText(this.bodyContent.getString())) {
renderFromBodyContent(this.bodyContent, this.tagWriter);
}
......@@ -79,7 +84,7 @@ public abstract class AbstractHtmlElementBodyTag extends AbstractHtmlElementTag
* override this to add additional content to the output.
*/
protected void renderFromBodyContent(BodyContent bodyContent, TagWriter tagWriter) throws JspException {
flushBufferedBodyContent(this.bodyContent);
flushBufferedBodyContent(bodyContent);
}
/**
......
......@@ -21,6 +21,7 @@ import java.util.Map;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.DynamicAttributes;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
......@@ -76,40 +77,58 @@ public abstract class AbstractHtmlElementTag extends AbstractDataBoundFormElemen
public static final String ONKEYDOWN_ATTRIBUTE = "onkeydown";
@Nullable
private String cssClass;
@Nullable
private String cssErrorClass;
@Nullable
private String cssStyle;
@Nullable
private String lang;
@Nullable
private String title;
@Nullable
private String dir;
@Nullable
private String tabindex;
@Nullable
private String onclick;
@Nullable
private String ondblclick;
@Nullable
private String onmousedown;
@Nullable
private String onmouseup;
@Nullable
private String onmouseover;
@Nullable
private String onmousemove;
@Nullable
private String onmouseout;
@Nullable
private String onkeypress;
@Nullable
private String onkeyup;
@Nullable
private String onkeydown;
@Nullable
private Map<String, Object> dynamicAttributes;
......@@ -125,6 +144,7 @@ public abstract class AbstractHtmlElementTag extends AbstractDataBoundFormElemen
* Get the value of the '{@code class}' attribute.
* May be a runtime expression.
*/
@Nullable
protected String getCssClass() {
return this.cssClass;
}
......@@ -141,6 +161,7 @@ public abstract class AbstractHtmlElementTag extends AbstractDataBoundFormElemen
* The CSS class to use when the field bound to a particular tag has errors.
* May be a runtime expression.
*/
@Nullable
protected String getCssErrorClass() {
return this.cssErrorClass;
}
......@@ -157,6 +178,7 @@ public abstract class AbstractHtmlElementTag extends AbstractDataBoundFormElemen
* Get the value of the '{@code style}' attribute.
* May be a runtime expression.
*/
@Nullable
protected String getCssStyle() {
return this.cssStyle;
}
......@@ -173,6 +195,7 @@ public abstract class AbstractHtmlElementTag extends AbstractDataBoundFormElemen
* Get the value of the '{@code lang}' attribute.
* May be a runtime expression.
*/
@Nullable
protected String getLang() {
return this.lang;
}
......@@ -189,6 +212,7 @@ public abstract class AbstractHtmlElementTag extends AbstractDataBoundFormElemen
* Get the value of the '{@code title}' attribute.
* May be a runtime expression.
*/
@Nullable
protected String getTitle() {
return this.title;
}
......@@ -205,6 +229,7 @@ public abstract class AbstractHtmlElementTag extends AbstractDataBoundFormElemen
* Get the value of the '{@code dir}' attribute.
* May be a runtime expression.
*/
@Nullable
protected String getDir() {
return this.dir;
}
......@@ -221,6 +246,7 @@ public abstract class AbstractHtmlElementTag extends AbstractDataBoundFormElemen
* Get the value of the '{@code tabindex}' attribute.
* May be a runtime expression.
*/
@Nullable
protected String getTabindex() {
return this.tabindex;
}
......@@ -237,6 +263,7 @@ public abstract class AbstractHtmlElementTag extends AbstractDataBoundFormElemen
* Get the value of the '{@code onclick}' attribute.
* May be a runtime expression.
*/
@Nullable
protected String getOnclick() {
return this.onclick;
}
......@@ -253,6 +280,7 @@ public abstract class AbstractHtmlElementTag extends AbstractDataBoundFormElemen
* Get the value of the '{@code ondblclick}' attribute.
* May be a runtime expression.
*/
@Nullable
protected String getOndblclick() {
return this.ondblclick;
}
......@@ -269,6 +297,7 @@ public abstract class AbstractHtmlElementTag extends AbstractDataBoundFormElemen
* Get the value of the '{@code onmousedown}' attribute.
* May be a runtime expression.
*/
@Nullable
protected String getOnmousedown() {
return this.onmousedown;
}
......@@ -285,6 +314,7 @@ public abstract class AbstractHtmlElementTag extends AbstractDataBoundFormElemen
* Get the value of the '{@code onmouseup}' attribute.
* May be a runtime expression.
*/
@Nullable
protected String getOnmouseup() {
return this.onmouseup;
}
......@@ -301,6 +331,7 @@ public abstract class AbstractHtmlElementTag extends AbstractDataBoundFormElemen
* Get the value of the '{@code onmouseover}' attribute.
* May be a runtime expression.
*/
@Nullable
protected String getOnmouseover() {
return this.onmouseover;
}
......@@ -317,6 +348,7 @@ public abstract class AbstractHtmlElementTag extends AbstractDataBoundFormElemen
* Get the value of the '{@code onmousemove}' attribute.
* May be a runtime expression.
*/
@Nullable
protected String getOnmousemove() {
return this.onmousemove;
}
......@@ -332,6 +364,7 @@ public abstract class AbstractHtmlElementTag extends AbstractDataBoundFormElemen
* Get the value of the '{@code onmouseout}' attribute.
* May be a runtime expression.
*/
@Nullable
protected String getOnmouseout() {
return this.onmouseout;
}
......@@ -348,6 +381,7 @@ public abstract class AbstractHtmlElementTag extends AbstractDataBoundFormElemen
* Get the value of the '{@code onkeypress}' attribute.
* May be a runtime expression.
*/
@Nullable
protected String getOnkeypress() {
return this.onkeypress;
}
......@@ -364,6 +398,7 @@ public abstract class AbstractHtmlElementTag extends AbstractDataBoundFormElemen
* Get the value of the '{@code onkeyup}' attribute.
* May be a runtime expression.
*/
@Nullable
protected String getOnkeyup() {
return this.onkeyup;
}
......@@ -380,6 +415,7 @@ public abstract class AbstractHtmlElementTag extends AbstractDataBoundFormElemen
* Get the value of the '{@code onkeydown}' attribute.
* May be a runtime expression.
*/
@Nullable
protected String getOnkeydown() {
return this.onkeydown;
}
......@@ -387,6 +423,7 @@ public abstract class AbstractHtmlElementTag extends AbstractDataBoundFormElemen
/**
* Get the map of dynamic attributes.
*/
@Nullable
protected Map<String, Object> getDynamicAttributes() {
return this.dynamicAttributes;
}
......@@ -395,7 +432,7 @@ public abstract class AbstractHtmlElementTag extends AbstractDataBoundFormElemen
* {@inheritDoc}
*/
@Override
public void setDynamicAttribute(String uri, String localName, Object value ) throws JspException {
public void setDynamicAttribute(String uri, String localName, Object value) throws JspException {
if (this.dynamicAttributes == null) {
this.dynamicAttributes = new HashMap<>();
}
......
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2018 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.
......@@ -18,6 +18,8 @@ package org.springframework.web.servlet.tags.form;
import javax.servlet.jsp.JspException;
import org.springframework.lang.Nullable;
/**
* Base class for databinding-aware JSP tags that render HTML form input element.
*
......@@ -63,12 +65,16 @@ public abstract class AbstractHtmlInputElementTag extends AbstractHtmlElementTag
public static final String READONLY_ATTRIBUTE = "readonly";
@Nullable
private String onfocus;
@Nullable
private String onblur;
@Nullable
private String onchange;
@Nullable
private String accesskey;
private boolean disabled;
......@@ -87,6 +93,7 @@ public abstract class AbstractHtmlInputElementTag extends AbstractHtmlElementTag
/**
* Get the value of the '{@code onfocus}' attribute.
*/
@Nullable
protected String getOnfocus() {
return this.onfocus;
}
......@@ -102,6 +109,7 @@ public abstract class AbstractHtmlInputElementTag extends AbstractHtmlElementTag
/**
* Get the value of the '{@code onblur}' attribute.
*/
@Nullable
protected String getOnblur() {
return this.onblur;
}
......@@ -117,6 +125,7 @@ public abstract class AbstractHtmlInputElementTag extends AbstractHtmlElementTag
/**
* Get the value of the '{@code onchange}' attribute.
*/
@Nullable
protected String getOnchange() {
return this.onchange;
}
......@@ -132,6 +141,7 @@ public abstract class AbstractHtmlInputElementTag extends AbstractHtmlElementTag
/**
* Get the value of the '{@code accesskey}' attribute.
*/
@Nullable
protected String getAccesskey() {
return this.accesskey;
}
......
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2018 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.
......@@ -23,6 +23,7 @@ import javax.servlet.jsp.JspException;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
......@@ -50,17 +51,20 @@ public abstract class AbstractMultiCheckedElementTag extends AbstractCheckedElem
* The {@link java.util.Collection}, {@link java.util.Map} or array of objects
* used to generate the '{@code input type="checkbox/radio"}' tags.
*/
@Nullable
private Object items;
/**
* The name of the property mapped to the '{@code value}' attribute
* of the '{@code input type="checkbox/radio"}' tag.
*/
@Nullable
private String itemValue;
/**
* The value to be displayed as part of the '{@code input type="checkbox/radio"}' tag.
*/
@Nullable
private String itemLabel;
/**
......@@ -71,6 +75,7 @@ public abstract class AbstractMultiCheckedElementTag extends AbstractCheckedElem
/**
* Delimiter to use between each '{@code input type="checkbox/radio"}' tags.
*/
@Nullable
private String delimiter;
......@@ -89,6 +94,7 @@ public abstract class AbstractMultiCheckedElementTag extends AbstractCheckedElem
* Get the {@link java.util.Collection}, {@link java.util.Map} or array of objects
* used to generate the '{@code input type="checkbox/radio"}' tags.
*/
@Nullable
protected Object getItems() {
return this.items;
}
......@@ -107,6 +113,7 @@ public abstract class AbstractMultiCheckedElementTag extends AbstractCheckedElem
* Get the name of the property mapped to the '{@code value}' attribute
* of the '{@code input type="checkbox/radio"}' tag.
*/
@Nullable
protected String getItemValue() {
return this.itemValue;
}
......@@ -125,6 +132,7 @@ public abstract class AbstractMultiCheckedElementTag extends AbstractCheckedElem
* Get the value to be displayed as part of the
* '{@code input type="checkbox/radio"}' tag.
*/
@Nullable
protected String getItemLabel() {
return this.itemLabel;
}
......@@ -142,6 +150,7 @@ public abstract class AbstractMultiCheckedElementTag extends AbstractCheckedElem
* Return the delimiter to be used between each
* '{@code input type="radio"}' tag.
*/
@Nullable
public String getDelimiter() {
return this.delimiter;
}
......@@ -236,8 +245,8 @@ public abstract class AbstractMultiCheckedElementTag extends AbstractCheckedElem
return SKIP_BODY;
}
private void writeObjectEntry(TagWriter tagWriter, String valueProperty,
String labelProperty, Object item, int itemIndex) throws JspException {
private void writeObjectEntry(TagWriter tagWriter, @Nullable String valueProperty,
@Nullable String labelProperty, Object item, int itemIndex) throws JspException {
BeanWrapper wrapper = PropertyAccessorFactory.forBeanPropertyAccess(item);
Object renderValue;
......@@ -254,8 +263,8 @@ public abstract class AbstractMultiCheckedElementTag extends AbstractCheckedElem
writeElementTag(tagWriter, item, renderValue, renderLabel, itemIndex);
}
private void writeMapEntry(TagWriter tagWriter, String valueProperty,
String labelProperty, Map.Entry<?, ?> entry, int itemIndex) throws JspException {
private void writeMapEntry(TagWriter tagWriter, @Nullable String valueProperty,
@Nullable String labelProperty, Map.Entry<?, ?> entry, int itemIndex) throws JspException {
Object mapKey = entry.getKey();
Object mapValue = entry.getValue();
......@@ -268,8 +277,8 @@ public abstract class AbstractMultiCheckedElementTag extends AbstractCheckedElem
writeElementTag(tagWriter, mapKey, renderValue, renderLabel, itemIndex);
}
private void writeElementTag(TagWriter tagWriter, Object item, Object value, Object label, int itemIndex)
throws JspException {
private void writeElementTag(TagWriter tagWriter, Object item, @Nullable Object value,
@Nullable Object label, int itemIndex) throws JspException {
tagWriter.startTag(getElement());
if (itemIndex > 0) {
......@@ -280,6 +289,7 @@ public abstract class AbstractMultiCheckedElementTag extends AbstractCheckedElem
}
tagWriter.startTag("input");
String id = resolveId();
Assert.state(id != null, "Attribute 'id' is required");
writeOptionalAttribute(tagWriter, "id", id);
writeOptionalAttribute(tagWriter, "name", getName());
writeOptionalAttributes(tagWriter);
......
......@@ -18,6 +18,9 @@ package org.springframework.web.servlet.tags.form;
import javax.servlet.jsp.JspException;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Abstract base class to provide common methods for implementing
* databinding-aware JSP tags for rendering a <i>single</i>
......@@ -33,11 +36,13 @@ public abstract class AbstractSingleCheckedElementTag extends AbstractCheckedEle
/**
* The value of the '{@code value}' attribute.
*/
@Nullable
private Object value;
/**
* The value of the '{@code label}' attribute.
*/
@Nullable
private Object label;
......@@ -52,6 +57,7 @@ public abstract class AbstractSingleCheckedElementTag extends AbstractCheckedEle
/**
* Get the value of the '{@code value}' attribute.
*/
@Nullable
protected Object getValue() {
return this.value;
}
......@@ -67,6 +73,7 @@ public abstract class AbstractSingleCheckedElementTag extends AbstractCheckedEle
/**
* Get the value of the '{@code label}' attribute.
*/
@Nullable
protected Object getLabel() {
return this.label;
}
......@@ -89,6 +96,7 @@ public abstract class AbstractSingleCheckedElementTag extends AbstractCheckedEle
Object resolvedLabel = evaluate("label", getLabel());
if (resolvedLabel != null) {
Assert.state(id != null, "Label id is required");
tagWriter.startTag("label");
tagWriter.writeAttribute("for", id);
tagWriter.appendValue(convertToDisplayString(resolvedLabel));
......
......@@ -18,6 +18,8 @@ package org.springframework.web.servlet.tags.form;
import javax.servlet.jsp.JspException;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.web.servlet.support.RequestDataValueProcessor;
/**
......@@ -77,10 +79,13 @@ public class ButtonTag extends AbstractHtmlElementTag {
public static final String DISABLED_ATTRIBUTE = "disabled";
@Nullable
private TagWriter tagWriter;
@Nullable
private String name;
@Nullable
private String value;
private boolean disabled;
......@@ -97,6 +102,7 @@ public class ButtonTag extends AbstractHtmlElementTag {
* Set the value of the '{@code name}' attribute.
*/
@Override
@Nullable
public String getName() {
return this.name;
}
......@@ -104,13 +110,14 @@ public class ButtonTag extends AbstractHtmlElementTag {
/**
* Set the value of the '{@code value}' attribute.
*/
public void setValue(String value) {
public void setValue(@Nullable String value) {
this.value = value;
}
/**
* Get the value of the '{@code value}' attribute.
*/
@Nullable
public String getValue() {
return this.value;
}
......@@ -150,7 +157,7 @@ public class ButtonTag extends AbstractHtmlElementTag {
* when the value is written.
*/
protected void writeValue(TagWriter tagWriter) throws JspException {
String valueToUse = (getValue() != null) ? getValue() : getDefaultValue();
String valueToUse = (getValue() != null ? getValue() : getDefaultValue());
tagWriter.writeAttribute("value", processFieldValue(getName(), valueToUse, getType()));
}
......@@ -176,6 +183,7 @@ public class ButtonTag extends AbstractHtmlElementTag {
*/
@Override
public int doEndTag() throws JspException {
Assert.state(this.tagWriter != null, "No TagWriter set");
this.tagWriter.endTag();
return EVAL_PAGE;
}
......
......@@ -23,6 +23,7 @@ import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.BodyTag;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
......@@ -209,6 +210,7 @@ public class ErrorsTag extends AbstractHtmlElementBodyTag implements BodyTag {
/**
* Stores any value that existed in the 'errors messages' before the tag was started.
*/
@Nullable
private Object oldMessages;
private boolean errorMessagesWereExposed;
......@@ -270,6 +272,7 @@ public class ErrorsTag extends AbstractHtmlElementBodyTag implements BodyTag {
* is not a validate attribute for the '{@code span}' element.
*/
@Override
@Nullable
protected String getName() throws JspException {
return null;
}
......
......@@ -28,6 +28,8 @@ import javax.servlet.jsp.PageContext;
import org.springframework.beans.PropertyAccessor;
import org.springframework.core.Conventions;
import org.springframework.http.HttpMethod;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
......@@ -288,33 +290,44 @@ public class FormTag extends AbstractHtmlElementTag {
private static final String TYPE_ATTRIBUTE = "type";
@Nullable
private TagWriter tagWriter;
private String modelAttribute = DEFAULT_COMMAND_NAME;
@Nullable
private String name;
@Nullable
private String action;
@Nullable
private String servletRelativeAction;
private String method = DEFAULT_METHOD;
@Nullable
private String target;
@Nullable
private String enctype;
@Nullable
private String acceptCharset;
@Nullable
private String onsubmit;
@Nullable
private String onreset;
@Nullable
private String autocomplete;
private String methodParam = DEFAULT_METHOD_PARAM;
/** Caching a previous nested path, so that it may be reset. */
@Nullable
private String previousNestedPath;
......@@ -347,6 +360,7 @@ public class FormTag extends AbstractHtmlElementTag {
* Get the value of the '{@code name}' attribute.
*/
@Override
@Nullable
protected String getName() throws JspException {
return this.name;
}
......@@ -355,13 +369,14 @@ public class FormTag extends AbstractHtmlElementTag {
* Set the value of the '{@code action}' attribute.
* <p>May be a runtime expression.
*/
public void setAction(String action) {
public void setAction(@Nullable String action) {
this.action = (action != null ? action : "");
}
/**
* Get the value of the '{@code action}' attribute.
*/
@Nullable
protected String getAction() {
return this.action;
}
......@@ -372,14 +387,15 @@ public class FormTag extends AbstractHtmlElementTag {
* <p>May be a runtime expression.
* @since 3.2.3
*/
public void setServletRelativeAction(String servletRelativeAction) {
this.servletRelativeAction = (servletRelativeAction != null ? servletRelativeAction : "");
public void setServletRelativeAction(@Nullable String servletRelativeAction) {
this.servletRelativeAction = servletRelativeAction;
}
/**
* Get the servlet-relative value of the '{@code action}' attribute.
* @since 3.2.3
*/
@Nullable
protected String getServletRelativeAction() {
return this.servletRelativeAction;
}
......@@ -410,6 +426,7 @@ public class FormTag extends AbstractHtmlElementTag {
/**
* Get the value of the '{@code target}' attribute.
*/
@Nullable
public String getTarget() {
return this.target;
}
......@@ -425,6 +442,7 @@ public class FormTag extends AbstractHtmlElementTag {
/**
* Get the value of the '{@code enctype}' attribute.
*/
@Nullable
protected String getEnctype() {
return this.enctype;
}
......@@ -440,6 +458,7 @@ public class FormTag extends AbstractHtmlElementTag {
/**
* Get the value of the '{@code acceptCharset}' attribute.
*/
@Nullable
protected String getAcceptCharset() {
return this.acceptCharset;
}
......@@ -455,6 +474,7 @@ public class FormTag extends AbstractHtmlElementTag {
/**
* Get the value of the '{@code onsubmit}' attribute.
*/
@Nullable
protected String getOnsubmit() {
return this.onsubmit;
}
......@@ -470,6 +490,7 @@ public class FormTag extends AbstractHtmlElementTag {
/**
* Get the value of the '{@code onreset}' attribute.
*/
@Nullable
protected String getOnreset() {
return this.onreset;
}
......@@ -485,6 +506,7 @@ public class FormTag extends AbstractHtmlElementTag {
/**
* Get the value of the '{@code autocomplete}' attribute.
*/
@Nullable
protected String getAutocomplete() {
return this.autocomplete;
}
......@@ -670,6 +692,7 @@ public class FormTag extends AbstractHtmlElementTag {
if (processor != null && request instanceof HttpServletRequest) {
writeHiddenFields(processor.getExtraHiddenFields((HttpServletRequest) request));
}
Assert.state(this.tagWriter != null, "No TagWriter set");
this.tagWriter.endTag();
return EVAL_PAGE;
}
......@@ -677,8 +700,9 @@ public class FormTag extends AbstractHtmlElementTag {
/**
* Writes the given values as hidden fields.
*/
private void writeHiddenFields(Map<String, String> hiddenFields) throws JspException {
private void writeHiddenFields(@Nullable Map<String, String> hiddenFields) throws JspException {
if (!CollectionUtils.isEmpty(hiddenFields)) {
Assert.state(this.tagWriter != null, "No TagWriter set");
this.tagWriter.appendValue("<div>\n");
for (String name : hiddenFields.keySet()) {
this.tagWriter.appendValue("<input type=\"hidden\" ");
......
......@@ -16,8 +16,11 @@
package org.springframework.web.servlet.tags.form;
import java.util.Map;
import javax.servlet.jsp.JspException;
import org.springframework.lang.Nullable;
/**
* The {@code <input>} tag renders an HTML 'input' tag with type 'text' using
* the bound value.
......@@ -241,19 +244,22 @@ public class InputTag extends AbstractHtmlInputElementTag {
public static final String ONSELECT_ATTRIBUTE = "onselect";
public static final String READONLY_ATTRIBUTE = "readonly";
public static final String AUTOCOMPLETE_ATTRIBUTE = "autocomplete";
@Nullable
private String size;
@Nullable
private String maxlength;
@Nullable
private String alt;
@Nullable
private String onselect;
@Nullable
private String autocomplete;
......@@ -268,6 +274,7 @@ public class InputTag extends AbstractHtmlInputElementTag {
/**
* Get the value of the '{@code size}' attribute.
*/
@Nullable
protected String getSize() {
return this.size;
}
......@@ -283,6 +290,7 @@ public class InputTag extends AbstractHtmlInputElementTag {
/**
* Get the value of the '{@code maxlength}' attribute.
*/
@Nullable
protected String getMaxlength() {
return this.maxlength;
}
......@@ -298,6 +306,7 @@ public class InputTag extends AbstractHtmlInputElementTag {
/**
* Get the value of the '{@code alt}' attribute.
*/
@Nullable
protected String getAlt() {
return this.alt;
}
......@@ -313,6 +322,7 @@ public class InputTag extends AbstractHtmlInputElementTag {
/**
* Get the value of the '{@code onselect}' attribute.
*/
@Nullable
protected String getOnselect() {
return this.onselect;
}
......@@ -328,6 +338,7 @@ public class InputTag extends AbstractHtmlInputElementTag {
/**
* Get the value of the '{@code autocomplete}' attribute.
*/
@Nullable
protected String getAutocomplete() {
return this.autocomplete;
}
......@@ -343,7 +354,8 @@ public class InputTag extends AbstractHtmlInputElementTag {
tagWriter.startTag("input");
writeDefaultAttributes(tagWriter);
if (!hasDynamicTypeAttribute()) {
Map<String, Object> attributes = getDynamicAttributes();
if (attributes == null || !attributes.containsKey("type")) {
tagWriter.writeAttribute("type", getType());
}
writeValue(tagWriter);
......@@ -359,10 +371,6 @@ public class InputTag extends AbstractHtmlInputElementTag {
return SKIP_BODY;
}
private boolean hasDynamicTypeAttribute() {
return getDynamicAttributes() != null && getDynamicAttributes().containsKey("type");
}
/**
* Writes the '{@code value}' attribute to the supplied {@link TagWriter}.
* Subclasses may choose to override this implementation to control exactly
......@@ -370,7 +378,14 @@ public class InputTag extends AbstractHtmlInputElementTag {
*/
protected void writeValue(TagWriter tagWriter) throws JspException {
String value = getDisplayString(getBoundValue(), getPropertyEditor());
String type = hasDynamicTypeAttribute() ? (String) getDynamicAttributes().get("type") : getType();
String type = null;
Map<String, Object> attributes = getDynamicAttributes();
if (attributes != null) {
type = (String) getDynamicAttributes().get("type");
}
if (type == null) {
type = getType();
}
tagWriter.writeAttribute("value", processFieldValue(getName(), value, type));
}
......
......@@ -18,6 +18,7 @@ package org.springframework.web.servlet.tags.form;
import javax.servlet.jsp.JspException;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
......@@ -190,21 +191,21 @@ public class LabelTag extends AbstractHtmlElementTag {
* The {@link TagWriter} instance being used.
* <p>Stored so we can close the tag on {@link #doEndTag()}.
*/
@Nullable
private TagWriter tagWriter;
/**
* The value of the '{@code for}' attribute.
*/
@Nullable
private String forId;
/**
* Set the value of the '{@code for}' attribute.
* <p>Defaults to the value of {@link #getPath}; may be a runtime expression.
* @throws IllegalArgumentException if the supplied value is {@code null}
*/
public void setFor(String forId) {
Assert.notNull(forId, "'forId' must not be null");
this.forId = forId;
}
......@@ -212,7 +213,8 @@ public class LabelTag extends AbstractHtmlElementTag {
* Get the value of the '{@code id}' attribute.
* <p>May be a runtime expression.
*/
public String getFor() {
@Nullable
protected String getFor() {
return this.forId;
}
......@@ -239,6 +241,7 @@ public class LabelTag extends AbstractHtmlElementTag {
* @return the value for the HTML '{@code name}' attribute
*/
@Override
@Nullable
protected String getName() throws JspException {
// This also suppresses the 'id' attribute (which is okay for a <label/>)
return null;
......@@ -273,6 +276,7 @@ public class LabelTag extends AbstractHtmlElementTag {
*/
@Override
public int doEndTag() throws JspException {
Assert.state(this.tagWriter != null, "No TagWriter set");
this.tagWriter.endTag();
return EVAL_PAGE;
}
......
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2018 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.
......@@ -20,7 +20,7 @@ import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyContent;
import javax.servlet.jsp.tagext.BodyTag;
import org.springframework.util.Assert;
import org.springframework.lang.Nullable;
import org.springframework.web.servlet.support.BindStatus;
import org.springframework.web.util.TagUtils;
......@@ -228,15 +228,19 @@ public class OptionTag extends AbstractHtmlElementBodyTag implements BodyTag {
/**
* The 'value' attribute of the rendered HTML {@code <option>} tag.
*/
@Nullable
private Object value;
/**
* The text body of the rendered HTML {@code <option>} tag.
*/
@Nullable
private String label;
@Nullable
private Object oldValue;
@Nullable
private Object oldDisplayValue;
private boolean disabled;
......@@ -252,6 +256,7 @@ public class OptionTag extends AbstractHtmlElementBodyTag implements BodyTag {
/**
* Get the 'value' attribute of the rendered HTML {@code <option>} tag.
*/
@Nullable
protected Object getValue() {
return this.value;
}
......@@ -275,13 +280,13 @@ public class OptionTag extends AbstractHtmlElementBodyTag implements BodyTag {
* <p>May be a runtime expression.
*/
public void setLabel(String label) {
Assert.notNull(label, "'label' must not be null");
this.label = label;
}
/**
* Get the text body of the rendered HTML {@code <option>} tag.
*/
@Nullable
protected String getLabel() {
return this.label;
}
......@@ -365,8 +370,8 @@ public class OptionTag extends AbstractHtmlElementBodyTag implements BodyTag {
}
/**
* Returns the value of the label for this '{@code option}' element.
* If the {@link #setLabel label} property is set then the resolved value
* Return the value of the label for this '{@code option}' element.
* <p>If the {@link #setLabel label} property is set then the resolved value
* of that property is used, otherwise the value of the {@code resolvedValue}
* argument is used.
*/
......@@ -388,6 +393,7 @@ public class OptionTag extends AbstractHtmlElementBodyTag implements BodyTag {
return SelectedValueComparator.isSelected(getBindStatus(), resolvedValue);
}
@Nullable
private Object resolveValue() throws JspException {
return evaluate(VALUE_VARIABLE_NAME, getValue());
}
......
......@@ -23,6 +23,7 @@ import javax.servlet.jsp.JspException;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.web.servlet.support.BindStatus;
......@@ -92,15 +93,17 @@ class OptionWriter {
private final BindStatus bindStatus;
@Nullable
private final String valueProperty;
@Nullable
private final String labelProperty;
private final boolean htmlEscape;
/**
* Creates a new {@code OptionWriter} for the supplied {@code objectSource}.
* Create a new {@code OptionWriter} for the supplied {@code objectSource}.
* @param optionSource the source of the {@code options} (never {@code null})
* @param bindStatus the {@link BindStatus} for the bound value (never {@code null})
* @param valueProperty the name of the property used to render {@code option} values
......@@ -108,8 +111,8 @@ class OptionWriter {
* @param labelProperty the name of the property used to render {@code option} labels
* (optional)
*/
public OptionWriter(
Object optionSource, BindStatus bindStatus, String valueProperty, String labelProperty, boolean htmlEscape) {
public OptionWriter(Object optionSource, BindStatus bindStatus,
@Nullable String valueProperty, @Nullable String labelProperty, boolean htmlEscape) {
Assert.notNull(optionSource, "'optionSource' must not be null");
Assert.notNull(bindStatus, "'bindStatus' must not be null");
......@@ -145,7 +148,7 @@ class OptionWriter {
}
/**
* Renders the inner '{@code option}' tags using the {@link #optionSource}.
* Render the inner '{@code option}' tags using the {@link #optionSource}.
* @see #doRenderFromCollection(java.util.Collection, TagWriter)
*/
private void renderFromArray(TagWriter tagWriter) throws JspException {
......@@ -153,7 +156,7 @@ class OptionWriter {
}
/**
* Renders the inner '{@code option}' tags using the supplied
* Render the inner '{@code option}' tags using the supplied
* {@link Map} as the source.
* @see #renderOption(TagWriter, Object, Object, Object)
*/
......@@ -173,7 +176,7 @@ class OptionWriter {
}
/**
* Renders the inner '{@code option}' tags using the {@link #optionSource}.
* Render the inner '{@code option}' tags using the {@link #optionSource}.
* @see #doRenderFromCollection(java.util.Collection, TagWriter)
*/
private void renderFromCollection(TagWriter tagWriter) throws JspException {
......@@ -181,7 +184,7 @@ class OptionWriter {
}
/**
* Renders the inner '{@code option}' tags using the {@link #optionSource}.
* Render the inner '{@code option}' tags using the {@link #optionSource}.
* @see #doRenderFromCollection(java.util.Collection, TagWriter)
*/
private void renderFromEnum(TagWriter tagWriter) throws JspException {
......@@ -189,7 +192,7 @@ class OptionWriter {
}
/**
* Renders the inner '{@code option}' tags using the supplied {@link Collection} of
* Render the inner '{@code option}' tags using the supplied {@link Collection} of
* objects as the source. The value of the {@link #valueProperty} field is used
* when rendering the '{@code value}' of the '{@code option}' and the value of the
* {@link #labelProperty} property is used when rendering the label.
......@@ -213,10 +216,12 @@ class OptionWriter {
}
/**
* Renders an HTML '{@code option}' with the supplied value and label. Marks the
* Render an HTML '{@code option}' with the supplied value and label. Marks the
* value as 'selected' if either the item itself or its value match the bound value.
*/
private void renderOption(TagWriter tagWriter, Object item, Object value, Object label) throws JspException {
private void renderOption(TagWriter tagWriter, Object item, @Nullable Object value, @Nullable Object label)
throws JspException {
tagWriter.startTag("option");
writeCommonAttributes(tagWriter);
......@@ -239,17 +244,17 @@ class OptionWriter {
}
/**
* Determines the display value of the supplied {@code Object},
* Determine the display value of the supplied {@code Object},
* HTML-escaped as required.
*/
private String getDisplayString(Object value) {
private String getDisplayString(@Nullable Object value) {
PropertyEditor editor = (value != null ? this.bindStatus.findEditor(value.getClass()) : null);
return ValueFormatter.getDisplayString(value, editor, this.htmlEscape);
}
/**
* Process the option value before it is written.
* The default implementation simply returns the same value unchanged.
* <p>The default implementation simply returns the same value unchanged.
*/
protected String processOptionValue(String resolvedValue) {
return resolvedValue;
......@@ -257,9 +262,9 @@ class OptionWriter {
/**
* Determine whether the supplied values matched the selected value.
* Delegates to {@link SelectedValueComparator#isSelected}.
* <p>Delegates to {@link SelectedValueComparator#isSelected}.
*/
private boolean isOptionSelected(Object resolvedValue) {
private boolean isOptionSelected(@Nullable Object resolvedValue) {
return SelectedValueComparator.isSelected(this.bindStatus, resolvedValue);
}
......@@ -271,7 +276,7 @@ class OptionWriter {
}
/**
* Writes default attributes configured to the supplied {@link TagWriter}.
* Write default attributes configured to the supplied {@link TagWriter}.
*/
protected void writeCommonAttributes(TagWriter tagWriter) throws JspException {
}
......
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2018 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.
......@@ -18,6 +18,7 @@ package org.springframework.web.servlet.tags.form;
import javax.servlet.jsp.JspException;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
......@@ -196,18 +197,21 @@ public class OptionsTag extends AbstractHtmlElementTag {
* The {@link java.util.Collection}, {@link java.util.Map} or array of
* objects used to generate the inner '{@code option}' tags.
*/
@Nullable
private Object items;
/**
* The name of the property mapped to the '{@code value}' attribute
* of the '{@code option}' tag.
*/
@Nullable
private String itemValue;
/**
* The name of the property mapped to the inner text of the
* '{@code option}' tag.
*/
@Nullable
private String itemLabel;
private boolean disabled;
......@@ -229,6 +233,7 @@ public class OptionsTag extends AbstractHtmlElementTag {
* of objects used to generate the inner '{@code option}' tags.
* <p>Typically a runtime expression.
*/
@Nullable
protected Object getItems() {
return this.items;
}
......@@ -248,6 +253,7 @@ public class OptionsTag extends AbstractHtmlElementTag {
* Return the name of the property mapped to the '{@code value}'
* attribute of the '{@code option}' tag.
*/
@Nullable
protected String getItemValue() {
return this.itemValue;
}
......@@ -265,6 +271,7 @@ public class OptionsTag extends AbstractHtmlElementTag {
* Get the name of the property mapped to the label (inner text) of the
* '{@code option}' tag.
*/
@Nullable
protected String getItemLabel() {
return this.itemLabel;
}
......@@ -342,9 +349,12 @@ public class OptionsTag extends AbstractHtmlElementTag {
*/
private class OptionsWriter extends OptionWriter {
@Nullable
private final String selectName;
public OptionsWriter(String selectName, Object optionSource, String valueProperty, String labelProperty) {
public OptionsWriter(@Nullable String selectName, Object optionSource,
@Nullable String valueProperty, @Nullable String labelProperty) {
super(optionSource, getBindStatus(), valueProperty, labelProperty, isHtmlEscape());
this.selectName = selectName;
}
......@@ -364,7 +374,6 @@ public class OptionsTag extends AbstractHtmlElementTag {
protected String processOptionValue(String value) {
return processFieldValue(this.selectName, value, "option");
}
}
}
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2018 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.
......
......@@ -20,6 +20,7 @@ import java.util.Collection;
import java.util.Map;
import javax.servlet.jsp.JspException;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.servlet.support.BindStatus;
......@@ -255,39 +256,45 @@ public class SelectTag extends AbstractHtmlInputElementTag {
/**
* The {@link Collection}, {@link Map} or array of objects used to generate the inner
* '{@code option}' tags.
* The {@link Collection}, {@link Map} or array of objects used to generate
* the inner '{@code option}' tags.
*/
@Nullable
private Object items;
/**
* The name of the property mapped to the '{@code value}' attribute
* of the '{@code option}' tag.
*/
@Nullable
private String itemValue;
/**
* The name of the property mapped to the inner text of the
* '{@code option}' tag.
*/
@Nullable
private String itemLabel;
/**
* The value of the HTML '{@code size}' attribute rendered
* on the final '{@code select}' element.
*/
@Nullable
private String size;
/**
* Indicates whether or not the '{@code select}' tag allows
* multiple-selections.
*/
@Nullable
private Object multiple;
/**
* The {@link TagWriter} instance that the output is being written.
* <p>Only used in conjunction with nested {@link OptionTag OptionTags}.
*/
@Nullable
private TagWriter tagWriter;
......@@ -299,7 +306,7 @@ public class SelectTag extends AbstractHtmlInputElementTag {
* <p>Typically a runtime expression.
* @param items the items that comprise the options of this selection
*/
public void setItems(Object items) {
public void setItems(@Nullable Object items) {
this.items = (items != null ? items : EMPTY);
}
......@@ -307,6 +314,7 @@ public class SelectTag extends AbstractHtmlInputElementTag {
* Get the value of the '{@code items}' attribute.
* <p>May be a runtime expression.
*/
@Nullable
protected Object getItems() {
return this.items;
}
......@@ -326,6 +334,7 @@ public class SelectTag extends AbstractHtmlInputElementTag {
* Get the value of the '{@code itemValue}' attribute.
* <p>May be a runtime expression.
*/
@Nullable
protected String getItemValue() {
return this.itemValue;
}
......@@ -343,6 +352,7 @@ public class SelectTag extends AbstractHtmlInputElementTag {
* Get the value of the '{@code itemLabel}' attribute.
* <p>May be a runtime expression.
*/
@Nullable
protected String getItemLabel() {
return this.itemLabel;
}
......@@ -358,6 +368,7 @@ public class SelectTag extends AbstractHtmlInputElementTag {
/**
* Get the value of the '{@code size}' attribute.
*/
@Nullable
protected String getSize() {
return this.size;
}
......@@ -374,6 +385,7 @@ public class SelectTag extends AbstractHtmlInputElementTag {
* Get the value of the HTML '{@code multiple}' attribute rendered
* on the final '{@code select}' element.
*/
@Nullable
protected Object getMultiple() {
return this.multiple;
}
......
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 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.
......@@ -21,6 +21,7 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.servlet.support.BindStatus;
......@@ -59,11 +60,7 @@ abstract class SelectedValueComparator {
* the supplied {@link BindStatus}. Equality in this case differs from standard Java equality and
* is described in more detail <a href="#equality-contract">here</a>.
*/
public static boolean isSelected(BindStatus bindStatus, Object candidateValue) {
if (bindStatus == null) {
return (candidateValue == null);
}
public static boolean isSelected(BindStatus bindStatus, @Nullable Object candidateValue) {
// Check obvious equality matches with the candidate first,
// both with the rendered value and with the original value.
Object boundValue = bindStatus.getValue();
......@@ -85,14 +82,16 @@ abstract class SelectedValueComparator {
// Non-null value but no obvious equality with the candidate value:
// go into more exhaustive comparisons.
boolean selected = false;
if (boundValue.getClass().isArray()) {
selected = collectionCompare(CollectionUtils.arrayToList(boundValue), candidateValue, bindStatus);
}
else if (boundValue instanceof Collection) {
selected = collectionCompare((Collection<?>) boundValue, candidateValue, bindStatus);
}
else if (boundValue instanceof Map) {
selected = mapCompare((Map<?, ?>) boundValue, candidateValue, bindStatus);
if (candidateValue != null) {
if (boundValue.getClass().isArray()) {
selected = collectionCompare(CollectionUtils.arrayToList(boundValue), candidateValue, bindStatus);
}
else if (boundValue instanceof Collection) {
selected = collectionCompare((Collection<?>) boundValue, candidateValue, bindStatus);
}
else if (boundValue instanceof Map) {
selected = mapCompare((Map<?, ?>) boundValue, candidateValue, bindStatus);
}
}
if (!selected) {
selected = exhaustiveCompare(boundValue, candidateValue, bindStatus.getEditor(), null);
......@@ -100,8 +99,8 @@ abstract class SelectedValueComparator {
return selected;
}
private static boolean collectionCompare(Collection<?> boundCollection, Object candidateValue,
BindStatus bindStatus) {
private static boolean collectionCompare(
Collection<?> boundCollection, Object candidateValue, BindStatus bindStatus) {
try {
if (boundCollection.contains(candidateValue)) {
return true;
......@@ -128,7 +127,7 @@ abstract class SelectedValueComparator {
private static boolean exhaustiveCollectionCompare(
Collection<?> collection, Object candidateValue, BindStatus bindStatus) {
Map<PropertyEditor, Object> convertedValueCache = new HashMap<>(1);
Map<PropertyEditor, Object> convertedValueCache = new HashMap<>();
PropertyEditor editor = null;
boolean candidateIsString = (candidateValue instanceof String);
if (!candidateIsString) {
......@@ -145,8 +144,8 @@ abstract class SelectedValueComparator {
return false;
}
private static boolean exhaustiveCompare(Object boundValue, Object candidate,
PropertyEditor editor, Map<PropertyEditor, Object> convertedValueCache) {
private static boolean exhaustiveCompare(@Nullable Object boundValue, @Nullable Object candidate,
@Nullable PropertyEditor editor, @Nullable Map<PropertyEditor, Object> convertedValueCache) {
String candidateDisplayString = ValueFormatter.getDisplayString(candidate, editor, false);
if (boundValue != null && boundValue.getClass().isEnum()) {
......
......@@ -195,7 +195,7 @@ public class TagWriter {
}
private TagStateEntry currentState() {
return this.tagState.peek();
return this.tagState.element();
}
......@@ -232,8 +232,10 @@ public class TagWriter {
*/
private static final class SafeWriter {
@Nullable
private PageContext pageContext;
@Nullable
private Writer writer;
public SafeWriter(PageContext pageContext) {
......@@ -255,7 +257,9 @@ public class TagWriter {
}
private Writer getWriterToUse() {
return (this.pageContext != null ? this.pageContext.getOut() : this.writer);
Writer writer = (this.pageContext != null ? this.pageContext.getOut() : this.writer);
Assert.state(writer != null, "No Writer available");
return writer;
}
}
......
......@@ -18,6 +18,8 @@ package org.springframework.web.servlet.tags.form;
import javax.servlet.jsp.JspException;
import org.springframework.lang.Nullable;
/**
* The {@code <textarea>} tag renders an HTML 'textarea'.
*
......@@ -225,13 +227,14 @@ public class TextareaTag extends AbstractHtmlInputElementTag {
public static final String ONSELECT_ATTRIBUTE = "onselect";
public static final String READONLY_ATTRIBUTE = "readonly";
@Nullable
private String rows;
@Nullable
private String cols;
@Nullable
private String onselect;
......@@ -246,6 +249,7 @@ public class TextareaTag extends AbstractHtmlInputElementTag {
/**
* Get the value of the '{@code rows}' attribute.
*/
@Nullable
protected String getRows() {
return this.rows;
}
......@@ -261,6 +265,7 @@ public class TextareaTag extends AbstractHtmlInputElementTag {
/**
* Get the value of the '{@code cols}' attribute.
*/
@Nullable
protected String getCols() {
return this.cols;
}
......@@ -276,6 +281,7 @@ public class TextareaTag extends AbstractHtmlInputElementTag {
/**
* Get the value of the '{@code onselect}' attribute.
*/
@Nullable
protected String getOnselect() {
return this.onselect;
}
......
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2018 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.
......@@ -18,6 +18,7 @@ package org.springframework.web.servlet.tags.form;
import java.beans.PropertyEditor;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
import org.springframework.web.util.HtmlUtils;
......@@ -43,7 +44,7 @@ abstract class ValueFormatter {
* as required. This version is <strong>not</strong> {@link PropertyEditor}-aware.
* @see #getDisplayString(Object, java.beans.PropertyEditor, boolean)
*/
public static String getDisplayString(Object value, boolean htmlEscape) {
public static String getDisplayString(@Nullable Object value, boolean htmlEscape) {
String displayValue = ObjectUtils.getDisplayString(value);
return (htmlEscape ? HtmlUtils.htmlEscape(displayValue) : displayValue);
}
......@@ -55,7 +56,9 @@ abstract class ValueFormatter {
* to obtain the display value.
* @see #getDisplayString(Object, boolean)
*/
public static String getDisplayString(Object value, PropertyEditor propertyEditor, boolean htmlEscape) {
public static String getDisplayString(
@Nullable Object value, @Nullable PropertyEditor propertyEditor, boolean htmlEscape) {
if (propertyEditor != null && !(value instanceof String)) {
try {
propertyEditor.setValue(value);
......
/**
* Spring's form tag library for JSP 2.0+.
* Supports JSP view implementations for Spring's web MVC framework.
* Spring's form tag library for JSP views in Spring's Web MVC framework.
* For more details on each tag, see the list of tags below with links to
* individual tag classes, or check the {@code spring-form.tld} file:
*
......@@ -22,4 +21,9 @@
* <li>{@link org.springframework.web.servlet.tags.form.TextareaTag The textarea tag}
* </ul>
*/
@NonNullApi
@NonNullFields
package org.springframework.web.servlet.tags.form;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册