Add <spring:argument> subtag for message/theme

Add a new <spring:argument> tag that cab be nested within
<spring:message> and <spring:theme>. The tag is based on the <fmt:param>
tag and uses conventions found throughout other Spring tags.

Issue: SPR-9678
This commit is contained in:
Nicholas Williams
2013-07-22 10:28:30 -07:00
committed by Phillip Webb
parent 50bd70f13d
commit f9b17a708f
8 changed files with 396 additions and 11 deletions

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2002-2013 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.servlet.tags;
import javax.servlet.jsp.JspTagException;
/**
* Allows implementing tag to utilize nested {@code spring:argument} tags.
*
* @author Nicholas Williams
* @since 4.0
* @see ArgumentTag
*/
public interface ArgumentAware {
/**
* Callback hook for nested spring:argument tags to pass their value
* to the parent tag.
* @param argument the result of the nested {@code spring:argument} tag
*/
void addArgument(Object argument) throws JspTagException;
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright 2002-2013 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.servlet.tags;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
/**
* JSP tag for collecting arguments and passing them to an {@link ArgumentAware} ancestor
* in the tag hierarchy.
*
* <p>This tag must be nested under an argument aware tag.
*
* @author Nicholas Williams
* @since 4.0
* @see MessageTag
* @see ThemeTag
*/
@SuppressWarnings("serial")
public class ArgumentTag extends BodyTagSupport {
private Object value;
private boolean valueSet;
// tag lifecycle
@Override
public int doEndTag() throws JspException {
Object argument = null;
if (this.valueSet) {
argument = this.value;
}
else if (getBodyContent() != null) {
// get the value from the tag body
argument = getBodyContent().getString().trim();
}
// find a param aware ancestor
ArgumentAware argumentAwareTag = (ArgumentAware) findAncestorWithClass(this,
ArgumentAware.class);
if (argumentAwareTag == null) {
throw new JspException(
"The argument tag must be a descendant of a tag that supports arguments");
}
argumentAwareTag.addArgument(argument);
return EVAL_PAGE;
}
// tag attribute mutators
/**
* Sets the value of the argument
*
* <p>
* Optional. If not set, the tag's body content is evaluated.
*
* @param value the parameter value
*/
public void setValue(Object value) {
this.value = value;
this.valueSet = true;
}
@Override
public void release() {
super.release();
this.value = null;
this.valueSet = false;
}
}

View File

@@ -18,6 +18,9 @@ package org.springframework.web.servlet.tags;
import java.io.IOException;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspTagException;
@@ -40,17 +43,22 @@ import org.springframework.web.util.TagUtils;
* <p>If "code" isn't set or cannot be resolved, "text" will be used as default
* message. Thus, this tag can also be used for HTML escaping of any texts.
*
* <p>Message arguments can be specified via the {@link #setArguments(Object) arguments}
* attribute or by using nested {@code &lt;spring:argument&gt;} tags.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @author Nicholas Williams
* @see #setCode
* @see #setText
* @see #setHtmlEscape
* @see #setJavaScriptEscape
* @see HtmlEscapeTag#setDefaultHtmlEscape
* @see org.springframework.web.util.WebUtils#HTML_ESCAPE_CONTEXT_PARAM
* @see ArgumentTag
*/
@SuppressWarnings("serial")
public class MessageTag extends HtmlEscapingAwareTag {
public class MessageTag extends HtmlEscapingAwareTag implements ArgumentAware {
/**
* Default separator for splitting an arguments String: a comma (",")
@@ -66,6 +74,8 @@ public class MessageTag extends HtmlEscapingAwareTag {
private String argumentSeparator = DEFAULT_ARGUMENT_SEPARATOR;
private List<Object> nestedArguments;
private String text;
private String var;
@@ -109,6 +119,11 @@ public class MessageTag extends HtmlEscapingAwareTag {
this.argumentSeparator = argumentSeparator;
}
@Override
public void addArgument(Object argument) throws JspTagException {
this.nestedArguments.add(argument);
}
/**
* Set the message text for this tag.
*/
@@ -146,6 +161,12 @@ public class MessageTag extends HtmlEscapingAwareTag {
}
@Override
protected final int doStartTagInternal() throws JspException, IOException {
this.nestedArguments = new LinkedList<Object>();
return EVAL_BODY_INCLUDE;
}
/**
* Resolves the message, escapes it if demanded,
* and writes it to the page (or exposes it as variable).
@@ -155,7 +176,7 @@ public class MessageTag extends HtmlEscapingAwareTag {
* @see #writeMessage(String)
*/
@Override
protected final int doStartTagInternal() throws JspException, IOException {
public int doEndTag() throws JspException {
try {
// Resolve the unescaped message.
String msg = resolveMessage();
@@ -172,13 +193,22 @@ public class MessageTag extends HtmlEscapingAwareTag {
writeMessage(msg);
}
return EVAL_BODY_INCLUDE;
return EVAL_PAGE;
}
catch (IOException ex) {
throw new JspTagException(ex.getMessage(), ex);
}
catch (NoSuchMessageException ex) {
throw new JspTagException(getNoSuchMessageExceptionDescription(ex));
}
}
@Override
public void release() {
super.release();
this.arguments = null;
}
/**
* Resolve the specified message into a concrete message String.
* The returned message String should be unescaped.
@@ -198,6 +228,11 @@ public class MessageTag extends HtmlEscapingAwareTag {
if (this.code != null || this.text != null) {
// We have a code or default text that we need to resolve.
Object[] argumentsArray = resolveArguments(this.arguments);
if(!this.nestedArguments.isEmpty()) {
argumentsArray = appendArguments(argumentsArray,
this.nestedArguments.toArray());
}
if (this.text != null) {
// We have a fallback text to consider.
return messageSource.getMessage(
@@ -214,6 +249,16 @@ public class MessageTag extends HtmlEscapingAwareTag {
return this.text;
}
private Object[] appendArguments(Object[] sourceArguments, Object[] additionalArguments) {
if(ObjectUtils.isEmpty(sourceArguments)) {
return additionalArguments;
}
Object[] arguments = new Object[sourceArguments.length + additionalArguments.length];
System.arraycopy(sourceArguments, 0, arguments, 0, sourceArguments.length);
System.arraycopy(additionalArguments, 0, arguments, sourceArguments.length, additionalArguments.length);
return arguments;
}
/**
* Resolve the given arguments Object into an arguments array.
* @param arguments the specified arguments Object

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -30,6 +30,9 @@ import org.springframework.context.NoSuchMessageException;
* <p>If "code" isn't set or cannot be resolved, "text" will be used
* as default message.
*
* <p>Message arguments can be specified via the {@link #setArguments(Object) arguments}
* attribute or by using nested {@code &lt;spring:argument&gt;} tags.
*
* @author Jean-Pierre Pawlak
* @author Juergen Hoeller
* @see org.springframework.ui.context.Theme
@@ -39,6 +42,7 @@ import org.springframework.context.NoSuchMessageException;
* @see #setHtmlEscape
* @see HtmlEscapeTag#setDefaultHtmlEscape
* @see org.springframework.web.util.WebUtils#HTML_ESCAPE_CONTEXT_PARAM
* @see ArgumentTag
*/
@SuppressWarnings("serial")
public class ThemeTag extends MessageTag {