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;
018
019import java.beans.PropertyEditor;
020import java.io.IOException;
021
022import javax.servlet.jsp.JspException;
023import javax.servlet.jsp.tagext.TagSupport;
024
025import org.springframework.lang.Nullable;
026import org.springframework.web.util.TagUtils;
027
028/**
029 * The {@code <transform>} tag provides transformation for reference data values
030 * from controllers and other objects inside a {@code spring:bind} tag (or a
031 * data-bound form element tag from Spring's form tag library).
032 *
033 * <p>The BindTag has a PropertyEditor that it uses to transform properties of
034 * a bean to a String, usable in HTML forms. This tag uses that PropertyEditor
035 * to transform objects passed into this tag.
036 *
037 * <table>
038 * <caption>Attribute Summary</caption>
039 * <thead>
040 * <tr>
041 * <th>Attribute</th>
042 * <th>Required?</th>
043 * <th>Runtime Expression?</th>
044 * <th>Description</th>
045 * </tr>
046 * </thead>
047 * <tbody>
048 * <tr>
049 * <td>htmlEscape</td>
050 * <td>false</td>
051 * <td>true</td>
052 * <td>Set HTML escaping for this tag, as boolean value. Overrides the default HTML
053 * escaping setting for the current page.</td>
054 * </tr>
055 * <tr>
056 * <td>scope</td>
057 * <td>false</td>
058 * <td>true</td>
059 * <td>The scope to use when exported the result to a variable. This attribute
060 * is only used when var is also set. Possible values are page, request, session
061 * and application.</td>
062 * </tr>
063 * <tr>
064 * <td>value</td>
065 * <td>true</td>
066 * <td>true</td>
067 * <td>The value to transform. This is the actual object you want to have
068 * transformed (for instance a Date). Using the PropertyEditor that is currently
069 * in use by the 'spring:bind' tag.</td>
070 * </tr>
071 * <tr>
072 * <td>var</td>
073 * <td>false</td>
074 * <td>true</td>
075 * <td>The string to use when binding the result to the page, request, session
076 * or application scope. If not specified, the result gets outputted to the
077 * writer (i.e. typically directly to the JSP).</td>
078 * </tr>
079 * </tbody>
080 * </table>
081 *
082 * @author Alef Arendsen
083 * @author Juergen Hoeller
084 * @since 20.09.2003
085 * @see BindTag
086 */
087@SuppressWarnings("serial")
088public class TransformTag extends HtmlEscapingAwareTag {
089
090        /** the value to transform using the appropriate property editor. */
091        @Nullable
092        private Object value;
093
094        /** the variable to put the result in. */
095        @Nullable
096        private String var;
097
098        /** the scope of the variable the result will be put in. */
099        private String scope = TagUtils.SCOPE_PAGE;
100
101
102        /**
103         * Set the value to transform, using the appropriate PropertyEditor
104         * from the enclosing BindTag.
105         * <p>The value can either be a plain value to transform (a hard-coded String
106         * value in a JSP or a JSP expression), or a JSP EL expression to be evaluated
107         * (transforming the result of the expression).
108         */
109        public void setValue(Object value) {
110                this.value = value;
111        }
112
113        /**
114         * Set PageContext attribute name under which to expose
115         * a variable that contains the result of the transformation.
116         * @see #setScope
117         * @see javax.servlet.jsp.PageContext#setAttribute
118         */
119        public void setVar(String var) {
120                this.var = var;
121        }
122
123        /**
124         * Set the scope to export the variable to.
125         * Default is SCOPE_PAGE ("page").
126         * @see #setVar
127         * @see org.springframework.web.util.TagUtils#SCOPE_PAGE
128         * @see javax.servlet.jsp.PageContext#setAttribute
129         */
130        public void setScope(String scope) {
131                this.scope = scope;
132        }
133
134
135        @Override
136        protected final int doStartTagInternal() throws JspException {
137                if (this.value != null) {
138                        // Find the containing EditorAwareTag (e.g. BindTag), if applicable.
139                        EditorAwareTag tag = (EditorAwareTag) TagSupport.findAncestorWithClass(this, EditorAwareTag.class);
140                        if (tag == null) {
141                                throw new JspException("TransformTag can only be used within EditorAwareTag (e.g. BindTag)");
142                        }
143
144                        // OK, let's obtain the editor...
145                        String result = null;
146                        PropertyEditor editor = tag.getEditor();
147                        if (editor != null) {
148                                // If an editor was found, edit the value.
149                                editor.setValue(this.value);
150                                result = editor.getAsText();
151                        }
152                        else {
153                                // Else, just do a toString.
154                                result = this.value.toString();
155                        }
156                        result = htmlEscape(result);
157                        if (this.var != null) {
158                                this.pageContext.setAttribute(this.var, result, TagUtils.getScope(this.scope));
159                        }
160                        else {
161                                try {
162                                        // Else, just print it out.
163                                        this.pageContext.getOut().print(result);
164                                }
165                                catch (IOException ex) {
166                                        throw new JspException(ex);
167                                }
168                        }
169                }
170
171                return SKIP_BODY;
172        }
173
174}