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 javax.servlet.jsp.JspException;
020
021import org.springframework.util.Assert;
022import org.springframework.util.StringUtils;
023
024/**
025 * Databinding-aware JSP tag for rendering an HTML '{@code label}' element
026 * that defines text that is associated with a single form element.
027 *
028 * <p>See the "formTags" showcase application that ships with the
029 * full Spring distribution for an example of this class in action.
030 *
031 * @author Rob Harrop
032 * @author Juergen Hoeller
033 * @since 2.0
034 */
035@SuppressWarnings("serial")
036public class LabelTag extends AbstractHtmlElementTag {
037
038        /**
039         * The HTML '{@code label}' tag.
040         */
041        private static final String LABEL_TAG = "label";
042
043        /**
044         * The name of the '{@code for}' attribute.
045         */
046        private static final String FOR_ATTRIBUTE = "for";
047
048
049        /**
050         * The {@link TagWriter} instance being used.
051         * <p>Stored so we can close the tag on {@link #doEndTag()}.
052         */
053        private TagWriter tagWriter;
054
055        /**
056         * The value of the '{@code for}' attribute.
057         */
058        private String forId;
059
060
061        /**
062         * Set the value of the '{@code for}' attribute.
063         * <p>Defaults to the value of {@link #getPath}; may be a runtime expression.
064         * @throws IllegalArgumentException if the supplied value is {@code null}
065         */
066        public void setFor(String forId) {
067                Assert.notNull(forId, "'forId' must not be null");
068                this.forId = forId;
069        }
070
071        /**
072         * Get the value of the '{@code id}' attribute.
073         * <p>May be a runtime expression.
074         */
075        public String getFor() {
076                return this.forId;
077        }
078
079
080        /**
081         * Writes the opening '{@code label}' tag and forces a block tag so
082         * that body content is written correctly.
083         * @return {@link javax.servlet.jsp.tagext.Tag#EVAL_BODY_INCLUDE}
084         */
085        @Override
086        protected int writeTagContent(TagWriter tagWriter) throws JspException {
087                tagWriter.startTag(LABEL_TAG);
088                tagWriter.writeAttribute(FOR_ATTRIBUTE, resolveFor());
089                writeDefaultAttributes(tagWriter);
090                tagWriter.forceBlock();
091                this.tagWriter = tagWriter;
092                return EVAL_BODY_INCLUDE;
093        }
094
095        /**
096         * Overrides {@code #getName()} to always return {@code null},
097         * because the '{@code name}' attribute is not supported by the
098         * '{@code label}' tag.
099         * @return the value for the HTML '{@code name}' attribute
100         */
101        @Override
102        protected String getName() throws JspException {
103                // This also suppresses the 'id' attribute (which is okay for a <label/>)
104                return null;
105        }
106
107        /**
108         * Determine the '{@code for}' attribute value for this tag,
109         * autogenerating one if none specified.
110         * @see #getFor()
111         * @see #autogenerateFor()
112         */
113        protected String resolveFor() throws JspException {
114                if (StringUtils.hasText(this.forId)) {
115                        return getDisplayString(evaluate(FOR_ATTRIBUTE, this.forId));
116                }
117                else {
118                        return autogenerateFor();
119                }
120        }
121
122        /**
123         * Autogenerate the '{@code for}' attribute value for this tag.
124         * <p>The default implementation delegates to {@link #getPropertyPath()},
125         * deleting invalid characters (such as "[" or "]").
126         */
127        protected String autogenerateFor() throws JspException {
128                return StringUtils.deleteAny(getPropertyPath(), "[]");
129        }
130
131        /**
132         * Close the '{@code label}' tag.
133         */
134        @Override
135        public int doEndTag() throws JspException {
136                this.tagWriter.endTag();
137                return EVAL_PAGE;
138        }
139
140        /**
141         * Disposes of the {@link TagWriter} instance.
142         */
143        @Override
144        public void doFinally() {
145                super.doFinally();
146                this.tagWriter = null;
147        }
148
149}