001/* 002 * Copyright 2002-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.servlet.tags.form; 018 019import java.beans.PropertyEditor; 020 021import javax.servlet.jsp.JspException; 022 023import org.springframework.lang.Nullable; 024import org.springframework.util.ObjectUtils; 025import org.springframework.web.servlet.tags.HtmlEscapingAwareTag; 026 027/** 028 * Base class for all JSP form tags. Provides utility methods for 029 * null-safe EL evaluation and for accessing and working with a {@link TagWriter}. 030 * 031 * <p>Subclasses should implement the {@link #writeTagContent(TagWriter)} to perform 032 * actual tag rendering. 033 * 034 * <p>Subclasses (or test classes) can override the {@link #createTagWriter()} method to 035 * redirect output to a {@link java.io.Writer} other than the {@link javax.servlet.jsp.JspWriter} 036 * associated with the current {@link javax.servlet.jsp.PageContext}. 037 * 038 * @author Rob Harrop 039 * @author Juergen Hoeller 040 * @since 2.0 041 */ 042@SuppressWarnings("serial") 043public abstract class AbstractFormTag extends HtmlEscapingAwareTag { 044 045 /** 046 * Evaluate the supplied value for the supplied attribute name. 047 * <p>The default implementation simply returns the given value as-is. 048 */ 049 @Nullable 050 protected Object evaluate(String attributeName, @Nullable Object value) throws JspException { 051 return value; 052 } 053 054 /** 055 * Optionally writes the supplied value under the supplied attribute name into the supplied 056 * {@link TagWriter}. In this case, the supplied value is {@link #evaluate evaluated} first 057 * and then the {@link ObjectUtils#getDisplayString String representation} is written as the 058 * attribute value. If the resultant {@code String} representation is {@code null} 059 * or empty, no attribute is written. 060 * @see TagWriter#writeOptionalAttributeValue(String, String) 061 */ 062 protected final void writeOptionalAttribute(TagWriter tagWriter, String attributeName, @Nullable String value) 063 throws JspException { 064 065 if (value != null) { 066 tagWriter.writeOptionalAttributeValue(attributeName, getDisplayString(evaluate(attributeName, value))); 067 } 068 } 069 070 /** 071 * Create the {@link TagWriter} which all output will be written to. By default, 072 * the {@link TagWriter} writes its output to the {@link javax.servlet.jsp.JspWriter} 073 * for the current {@link javax.servlet.jsp.PageContext}. Subclasses may choose to 074 * change the {@link java.io.Writer} to which output is actually written. 075 */ 076 protected TagWriter createTagWriter() { 077 return new TagWriter(this.pageContext); 078 } 079 080 /** 081 * Provide a simple template method that calls {@link #createTagWriter()} and passes 082 * the created {@link TagWriter} to the {@link #writeTagContent(TagWriter)} method. 083 * @return the value returned by {@link #writeTagContent(TagWriter)} 084 */ 085 @Override 086 protected final int doStartTagInternal() throws Exception { 087 return writeTagContent(createTagWriter()); 088 } 089 090 /** 091 * Get the display value of the supplied {@code Object}, HTML escaped 092 * as required. This version is <strong>not</strong> {@link PropertyEditor}-aware. 093 */ 094 protected String getDisplayString(@Nullable Object value) { 095 return ValueFormatter.getDisplayString(value, isHtmlEscape()); 096 } 097 098 /** 099 * Get the display value of the supplied {@code Object}, HTML escaped 100 * as required. If the supplied value is not a {@link String} and the supplied 101 * {@link PropertyEditor} is not null then the {@link PropertyEditor} is used 102 * to obtain the display value. 103 */ 104 protected String getDisplayString(@Nullable Object value, @Nullable PropertyEditor propertyEditor) { 105 return ValueFormatter.getDisplayString(value, propertyEditor, isHtmlEscape()); 106 } 107 108 /** 109 * Overridden to default to {@code true} in case of no explicit default given. 110 */ 111 @Override 112 protected boolean isDefaultHtmlEscape() { 113 Boolean defaultHtmlEscape = getRequestContext().getDefaultHtmlEscape(); 114 return (defaultHtmlEscape == null || defaultHtmlEscape.booleanValue()); 115 } 116 117 118 /** 119 * Subclasses should implement this method to perform tag content rendering. 120 * @return valid tag render instruction as per {@link javax.servlet.jsp.tagext.Tag#doStartTag()}. 121 */ 122 protected abstract int writeTagContent(TagWriter tagWriter) throws JspException; 123 124}