Skip to content

Commit 66cfe9f

Browse files
committed
Merge pull request spring-projects#297 from beamerblvd/SPR-9678
# By Nicholas Williams * SPR-9678: Add <spring:argument> subtag for message/theme Ensure ParamTag release resources Fix malformed UrlTag Javadoc Update TLD versions to 4.0
2 parents 6580d6b + f9b17a7 commit 66cfe9f

File tree

12 files changed

+456
-23
lines changed

12 files changed

+456
-23
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright 2002-2013 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.web.servlet.tags;
18+
19+
import javax.servlet.jsp.JspTagException;
20+
21+
/**
22+
* Allows implementing tag to utilize nested {@code spring:argument} tags.
23+
*
24+
* @author Nicholas Williams
25+
* @since 4.0
26+
* @see ArgumentTag
27+
*/
28+
public interface ArgumentAware {
29+
30+
/**
31+
* Callback hook for nested spring:argument tags to pass their value
32+
* to the parent tag.
33+
* @param argument the result of the nested {@code spring:argument} tag
34+
*/
35+
void addArgument(Object argument) throws JspTagException;
36+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
* Copyright 2002-2013 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.web.servlet.tags;
18+
19+
import javax.servlet.jsp.JspException;
20+
import javax.servlet.jsp.tagext.BodyTagSupport;
21+
22+
/**
23+
* JSP tag for collecting arguments and passing them to an {@link ArgumentAware} ancestor
24+
* in the tag hierarchy.
25+
*
26+
* <p>This tag must be nested under an argument aware tag.
27+
*
28+
* @author Nicholas Williams
29+
* @since 4.0
30+
* @see MessageTag
31+
* @see ThemeTag
32+
*/
33+
@SuppressWarnings("serial")
34+
public class ArgumentTag extends BodyTagSupport {
35+
36+
private Object value;
37+
38+
private boolean valueSet;
39+
40+
// tag lifecycle
41+
42+
@Override
43+
public int doEndTag() throws JspException {
44+
Object argument = null;
45+
if (this.valueSet) {
46+
argument = this.value;
47+
}
48+
else if (getBodyContent() != null) {
49+
// get the value from the tag body
50+
argument = getBodyContent().getString().trim();
51+
}
52+
53+
// find a param aware ancestor
54+
ArgumentAware argumentAwareTag = (ArgumentAware) findAncestorWithClass(this,
55+
ArgumentAware.class);
56+
if (argumentAwareTag == null) {
57+
throw new JspException(
58+
"The argument tag must be a descendant of a tag that supports arguments");
59+
}
60+
61+
argumentAwareTag.addArgument(argument);
62+
63+
return EVAL_PAGE;
64+
}
65+
66+
// tag attribute mutators
67+
68+
/**
69+
* Sets the value of the argument
70+
*
71+
* <p>
72+
* Optional. If not set, the tag's body content is evaluated.
73+
*
74+
* @param value the parameter value
75+
*/
76+
public void setValue(Object value) {
77+
this.value = value;
78+
this.valueSet = true;
79+
}
80+
81+
@Override
82+
public void release() {
83+
super.release();
84+
this.value = null;
85+
this.valueSet = false;
86+
}
87+
88+
}

spring-webmvc/src/main/java/org/springframework/web/servlet/tags/MessageTag.java

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818

1919
import java.io.IOException;
2020
import java.util.Collection;
21+
import java.util.LinkedList;
22+
import java.util.List;
23+
2124
import javax.servlet.jsp.JspException;
2225
import javax.servlet.jsp.JspTagException;
2326

@@ -40,17 +43,22 @@
4043
* <p>If "code" isn't set or cannot be resolved, "text" will be used as default
4144
* message. Thus, this tag can also be used for HTML escaping of any texts.
4245
*
46+
* <p>Message arguments can be specified via the {@link #setArguments(Object) arguments}
47+
* attribute or by using nested {@code &lt;spring:argument&gt;} tags.
48+
*
4349
* @author Rod Johnson
4450
* @author Juergen Hoeller
51+
* @author Nicholas Williams
4552
* @see #setCode
4653
* @see #setText
4754
* @see #setHtmlEscape
4855
* @see #setJavaScriptEscape
4956
* @see HtmlEscapeTag#setDefaultHtmlEscape
5057
* @see org.springframework.web.util.WebUtils#HTML_ESCAPE_CONTEXT_PARAM
58+
* @see ArgumentTag
5159
*/
5260
@SuppressWarnings("serial")
53-
public class MessageTag extends HtmlEscapingAwareTag {
61+
public class MessageTag extends HtmlEscapingAwareTag implements ArgumentAware {
5462

5563
/**
5664
* Default separator for splitting an arguments String: a comma (",")
@@ -66,6 +74,8 @@ public class MessageTag extends HtmlEscapingAwareTag {
6674

6775
private String argumentSeparator = DEFAULT_ARGUMENT_SEPARATOR;
6876

77+
private List<Object> nestedArguments;
78+
6979
private String text;
7080

7181
private String var;
@@ -109,6 +119,11 @@ public void setArgumentSeparator(String argumentSeparator) {
109119
this.argumentSeparator = argumentSeparator;
110120
}
111121

122+
@Override
123+
public void addArgument(Object argument) throws JspTagException {
124+
this.nestedArguments.add(argument);
125+
}
126+
112127
/**
113128
* Set the message text for this tag.
114129
*/
@@ -146,6 +161,12 @@ public void setJavaScriptEscape(boolean javaScriptEscape) throws JspException {
146161
}
147162

148163

164+
@Override
165+
protected final int doStartTagInternal() throws JspException, IOException {
166+
this.nestedArguments = new LinkedList<Object>();
167+
return EVAL_BODY_INCLUDE;
168+
}
169+
149170
/**
150171
* Resolves the message, escapes it if demanded,
151172
* and writes it to the page (or exposes it as variable).
@@ -155,7 +176,7 @@ public void setJavaScriptEscape(boolean javaScriptEscape) throws JspException {
155176
* @see #writeMessage(String)
156177
*/
157178
@Override
158-
protected final int doStartTagInternal() throws JspException, IOException {
179+
public int doEndTag() throws JspException {
159180
try {
160181
// Resolve the unescaped message.
161182
String msg = resolveMessage();
@@ -172,13 +193,22 @@ protected final int doStartTagInternal() throws JspException, IOException {
172193
writeMessage(msg);
173194
}
174195

175-
return EVAL_BODY_INCLUDE;
196+
return EVAL_PAGE;
197+
}
198+
catch (IOException ex) {
199+
throw new JspTagException(ex.getMessage(), ex);
176200
}
177201
catch (NoSuchMessageException ex) {
178202
throw new JspTagException(getNoSuchMessageExceptionDescription(ex));
179203
}
180204
}
181205

206+
@Override
207+
public void release() {
208+
super.release();
209+
this.arguments = null;
210+
}
211+
182212
/**
183213
* Resolve the specified message into a concrete message String.
184214
* The returned message String should be unescaped.
@@ -198,6 +228,11 @@ protected String resolveMessage() throws JspException, NoSuchMessageException {
198228
if (this.code != null || this.text != null) {
199229
// We have a code or default text that we need to resolve.
200230
Object[] argumentsArray = resolveArguments(this.arguments);
231+
if(!this.nestedArguments.isEmpty()) {
232+
argumentsArray = appendArguments(argumentsArray,
233+
this.nestedArguments.toArray());
234+
}
235+
201236
if (this.text != null) {
202237
// We have a fallback text to consider.
203238
return messageSource.getMessage(
@@ -214,6 +249,16 @@ protected String resolveMessage() throws JspException, NoSuchMessageException {
214249
return this.text;
215250
}
216251

252+
private Object[] appendArguments(Object[] sourceArguments, Object[] additionalArguments) {
253+
if(ObjectUtils.isEmpty(sourceArguments)) {
254+
return additionalArguments;
255+
}
256+
Object[] arguments = new Object[sourceArguments.length + additionalArguments.length];
257+
System.arraycopy(sourceArguments, 0, arguments, 0, sourceArguments.length);
258+
System.arraycopy(additionalArguments, 0, arguments, sourceArguments.length, additionalArguments.length);
259+
return arguments;
260+
}
261+
217262
/**
218263
* Resolve the given arguments Object into an arguments array.
219264
* @param arguments the specified arguments Object

spring-webmvc/src/main/java/org/springframework/web/servlet/tags/ParamTag.java

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2013 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -26,6 +26,7 @@
2626
* <p>This tag must be nested under a param aware tag.
2727
*
2828
* @author Scott Andrews
29+
* @author Nicholas Williams
2930
* @since 3.0
3031
* @see Param
3132
* @see UrlTag
@@ -37,16 +38,16 @@ public class ParamTag extends BodyTagSupport {
3738

3839
private String value;
3940

40-
private Param param;
41+
private boolean valueSet;
4142

4243
// tag lifecycle
4344

4445
@Override
4546
public int doEndTag() throws JspException {
46-
param = new Param();
47-
param.setName(name);
48-
if (value != null) {
49-
param.setValue(value);
47+
Param param = new Param();
48+
param.setName(this.name);
49+
if (this.valueSet) {
50+
param.setValue(this.value);
5051
}
5152
else if (getBodyContent() != null) {
5253
// get the value from the tag body
@@ -90,6 +91,15 @@ public void setName(String name) {
9091
*/
9192
public void setValue(String value) {
9293
this.value = value;
94+
this.valueSet = true;
95+
}
96+
97+
@Override
98+
public void release() {
99+
super.release();
100+
this.name = null;
101+
this.value = null;
102+
this.valueSet = false;
93103
}
94104

95105
}

spring-webmvc/src/main/java/org/springframework/web/servlet/tags/ThemeTag.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2013 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -30,6 +30,9 @@
3030
* <p>If "code" isn't set or cannot be resolved, "text" will be used
3131
* as default message.
3232
*
33+
* <p>Message arguments can be specified via the {@link #setArguments(Object) arguments}
34+
* attribute or by using nested {@code &lt;spring:argument&gt;} tags.
35+
*
3336
* @author Jean-Pierre Pawlak
3437
* @author Juergen Hoeller
3538
* @see org.springframework.ui.context.Theme
@@ -39,6 +42,7 @@
3942
* @see #setHtmlEscape
4043
* @see HtmlEscapeTag#setDefaultHtmlEscape
4144
* @see org.springframework.web.util.WebUtils#HTML_ESCAPE_CONTEXT_PARAM
45+
* @see ArgumentTag
4246
*/
4347
@SuppressWarnings("serial")
4448
public class ThemeTag extends MessageTag {

spring-webmvc/src/main/java/org/springframework/web/servlet/tags/UrlTag.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
* over direct EL substitution as the values are URL encoded. Failure to properly
5858
* encode URL can leave an application vulnerable to XSS and other injection attacks.
5959
*
60-
* <p>URLs can be HTML/XML escaped by setting the {@link #setHtmlEscape(String)
60+
* <p>URLs can be HTML/XML escaped by setting the {@link #setHtmlEscape(boolean)
6161
* 'htmlEscape'} attribute to 'true'. Detects an HTML escaping setting, either on
6262
* this tag instance, the page level, or the {@code web.xml} level. The default
6363
* is 'false'. When setting the URL value into a variable, escaping is not recommended.

spring-webmvc/src/main/resources/META-INF/spring-form.tld

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
version="2.0">
66

77
<description>Spring Framework JSP Form Tag Library</description>
8-
<tlib-version>3.0</tlib-version>
8+
<tlib-version>4.0</tlib-version>
99
<short-name>form</short-name>
1010
<uri>http://www.springframework.org/tags/form</uri>
1111

0 commit comments

Comments
 (0)