You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by lu...@apache.org on 2020/10/15 05:22:10 UTC
[struts] 01/01: Introduces a TagAttribute class as a wrapper around
raw String attributes
This is an automated email from the ASF dual-hosted git repository.
lukaszlenart pushed a commit to branch tag-attribute
in repository https://gitbox.apache.org/repos/asf/struts.git
commit 5077c211187554b4e001f71a3b1c0d99bd4a2183
Author: Lukasz Lenart <lu...@apache.org>
AuthorDate: Thu Oct 15 07:21:57 2020 +0200
Introduces a TagAttribute class as a wrapper around raw String attributes
---
.../org/apache/struts2/components/Component.java | 54 +++++++++++----
.../apache/struts2/components/DoubleSelect.java | 2 +-
.../java/org/apache/struts2/components/Form.java | 11 +--
.../org/apache/struts2/components/FormButton.java | 16 +++--
.../struts2/components/ServletUrlRenderer.java | 16 +++--
.../java/org/apache/struts2/components/UIBean.java | 26 +++----
.../org/apache/struts2/views/TagAttribute.java | 79 ++++++++++++++++++++++
.../views/freemarker/StrutsBeanWrapper.java | 15 +++-
.../views/freemarker/TagAttributeAdapter.java | 47 +++++++++++++
.../apache/struts2/components/FormButtonTest.java | 29 ++++----
.../org/apache/struts2/components/UIBeanTest.java | 19 +++---
.../org/apache/struts2/views/java/Attributes.java | 4 ++
.../struts2/views/java/simple/CheckboxHandler.java | 6 +-
.../views/java/simple/DateTextFieldHandler.java | 3 +-
.../struts2/components/PortletUrlRenderer.java | 12 ++--
15 files changed, 261 insertions(+), 78 deletions(-)
diff --git a/core/src/main/java/org/apache/struts2/components/Component.java b/core/src/main/java/org/apache/struts2/components/Component.java
index e6c13d3..e09048c 100644
--- a/core/src/main/java/org/apache/struts2/components/Component.java
+++ b/core/src/main/java/org/apache/struts2/components/Component.java
@@ -22,8 +22,8 @@ import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.util.TextParseUtil;
import com.opensymphony.xwork2.util.ValueStack;
import org.apache.commons.lang3.BooleanUtils;
-import org.apache.commons.lang3.reflect.MethodUtils;
import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.reflect.MethodUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.StrutsConstants;
@@ -32,6 +32,7 @@ import org.apache.struts2.dispatcher.mapper.ActionMapper;
import org.apache.struts2.dispatcher.mapper.ActionMapping;
import org.apache.struts2.util.ComponentUtils;
import org.apache.struts2.util.FastByteArrayOutputStream;
+import org.apache.struts2.views.TagAttribute;
import org.apache.struts2.views.annotations.StrutsTagAttribute;
import org.apache.struts2.views.jsp.TagUtils;
import org.apache.struts2.views.util.UrlHelper;
@@ -65,7 +66,7 @@ public class Component {
protected boolean devMode = false;
protected ValueStack stack;
- protected Map parameters;
+ protected Map<String, Object> parameters;
protected ActionMapper actionMapper;
protected boolean throwExceptionOnELFailure;
private UrlHelper urlHelper;
@@ -220,6 +221,10 @@ public class Component {
return (String) findValue(expr, String.class);
}
+ protected TagAttribute findString(TagAttribute attribute) {
+ return findValue(attribute, String.class);
+ }
+
/**
* Evaluates the OGNL stack to find a String value.
* <br>
@@ -276,7 +281,7 @@ public class Component {
}
/**
- * If altsyntax (%{...}) is applied, simply strip the "%{" and "}" off.
+ * If altsyntax (%{...}) is applied, simply strip the "%{" and "}" off.
* @param expr the expression (must be not null)
* @return the stripped expression if altSyntax is enabled. Otherwise
* the parameter expression is returned as is.
@@ -296,7 +301,7 @@ public class Component {
/**
* Adds the surrounding %{ } to the expression for proper processing.
* @param expr the expression.
- * @return the modified expression if altSyntax is enabled, or the parameter
+ * @return the modified expression if altSyntax is enabled, or the parameter
* expression otherwise.
*/
protected String completeExpressionIfAltSyntax(String expr) {
@@ -319,6 +324,13 @@ public class Component {
return expr;
}
+ protected TagAttribute findStringIfAltSyntax(TagAttribute attribute) {
+ if (altSyntax()) {
+ return findString(attribute);
+ }
+ return attribute;
+ }
+
/**
* <p>
* Evaluates the OGNL stack to find an Object value.
@@ -368,7 +380,7 @@ public class Component {
* @param toType the type expected to find.
* @return the Object found, or <tt>null</tt> if not found.
*/
- protected Object findValue(String expr, Class toType) {
+ protected Object findValue(String expr, Class<?> toType) {
if (altSyntax() && toType == String.class) {
if (ComponentUtils.containsExpression(expr)) {
return TextParseUtil.translateVariables('%', expr, stack);
@@ -382,6 +394,25 @@ public class Component {
}
}
+ protected TagAttribute findValue(TagAttribute attribute, Class<?> toType) {
+ if (altSyntax() && toType == String.class) {
+ if (attribute.isExpression() && !attribute.isEvaluated()) {
+ String translateVariables = TextParseUtil.translateVariables('%', attribute.getValue(), stack);
+ return TagAttribute.evaluated(translateVariables);
+ } else {
+ return attribute;
+ }
+ } else {
+ Object value = getStack().findValue(attribute.stripedExpression(), toType, throwExceptionOnELFailure);
+
+ if (value == null) {
+ return TagAttribute.NULL;
+ } else {
+ return TagAttribute.evaluated(String.valueOf(value));
+ }
+ }
+ }
+
/**
* Renders an action URL by consulting the {@link org.apache.struts2.dispatcher.mapper.ActionMapper}.
* @param action the action
@@ -440,13 +471,12 @@ public class Component {
*
* @param params the parameters to copy.
*/
- public void copyParams(Map params) {
+ public void copyParams(Map<String, ?> params) {
stack.push(parameters);
stack.push(this);
try {
- for (Object o : params.entrySet()) {
- Map.Entry entry = (Map.Entry) o;
- String key = (String) entry.getKey();
+ for (Map.Entry<String, ?> entry : params.entrySet()) {
+ String key = entry.getKey();
if (key.indexOf('-') >= 0) {
// UI component attributes may contain hypens (e.g. data-ajax), but ognl
@@ -480,7 +510,7 @@ public class Component {
* Gets the parameters.
* @return the parameters. Is never <tt>null</tt>.
*/
- public Map getParameters() {
+ public Map<String, Object> getParameters() {
return parameters;
}
@@ -523,9 +553,9 @@ public class Component {
/**
* Override to set if body content should be HTML-escaped.
- *
+ *
* @return always true (default) for this component.
- *
+ *
* @since 2.6
*/
public boolean escapeHtmlBody() {
diff --git a/core/src/main/java/org/apache/struts2/components/DoubleSelect.java b/core/src/main/java/org/apache/struts2/components/DoubleSelect.java
index a6f96b1..78a9eed 100644
--- a/core/src/main/java/org/apache/struts2/components/DoubleSelect.java
+++ b/core/src/main/java/org/apache/struts2/components/DoubleSelect.java
@@ -57,7 +57,7 @@ public class DoubleSelect extends DoubleListUIBean {
public void evaluateExtraParams() {
super.evaluateExtraParams();
StringBuilder onchangeParam = new StringBuilder();
- onchangeParam.append(getParameters().get("id")).append("Redirect(this.selectedIndex)");
+ onchangeParam.append(getId().getValue()).append("Redirect(this.selectedIndex)");
if(StringUtils.isNotEmpty(this.onchange)) {
onchangeParam.append(";").append(this.onchange);
}
diff --git a/core/src/main/java/org/apache/struts2/components/Form.java b/core/src/main/java/org/apache/struts2/components/Form.java
index 9758cf3..a5480dd 100644
--- a/core/src/main/java/org/apache/struts2/components/Form.java
+++ b/core/src/main/java/org/apache/struts2/components/Form.java
@@ -30,6 +30,7 @@ import com.opensymphony.xwork2.validator.*;
import com.opensymphony.xwork2.validator.validators.VisitorFieldValidator;
import org.apache.commons.lang3.StringUtils;
import org.apache.struts2.dispatcher.mapper.ActionMapping;
+import org.apache.struts2.views.TagAttribute;
import org.apache.struts2.views.annotations.StrutsTag;
import org.apache.struts2.views.annotations.StrutsTagAttribute;
import org.apache.struts2.views.jsp.TagUtils;
@@ -169,9 +170,9 @@ public class Form extends ClosingUIBean {
if (name == null) {
//make the name the same as the id
- String id = (String) getParameters().get("id");
- if (StringUtils.isNotEmpty(id)) {
- addParameter("name", id);
+ TagAttribute id = (TagAttribute) getParameters().get("id");
+ if (id != null && !id.isNull()) {
+ addParameter("name", id.getValue());
}
}
@@ -220,8 +221,8 @@ public class Form extends ClosingUIBean {
*/
@Override
protected void populateComponentHtmlId(Form form) {
- if (id != null) {
- addParameter("id", escape(id));
+ if (!id.isNull()) {
+ addParameter("id", id.escaped());
}
// if no id given, it will be tried to generate it from the action attribute
diff --git a/core/src/main/java/org/apache/struts2/components/FormButton.java b/core/src/main/java/org/apache/struts2/components/FormButton.java
index 7dcc7ae..4340b01 100644
--- a/core/src/main/java/org/apache/struts2/components/FormButton.java
+++ b/core/src/main/java/org/apache/struts2/components/FormButton.java
@@ -21,6 +21,7 @@ package org.apache.struts2.components;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import org.apache.struts2.views.TagAttribute;
import org.apache.struts2.views.annotations.StrutsTagAttribute;
import org.apache.struts2.dispatcher.mapper.ActionMapper;
import org.apache.struts2.dispatcher.mapper.ActionMapping;
@@ -98,32 +99,33 @@ public abstract class FormButton extends ClosingUIBean {
* </ol>
*/
protected void populateComponentHtmlId(Form form) {
- String _tmp_id = "";
- if (id != null) {
+ TagAttribute _tmp_id = TagAttribute.EMPTY;
+ if (!id.isNull()) {
// this check is needed for backwards compatibility with 2.1.x
_tmp_id = findStringIfAltSyntax(id);
}
else {
if (form != null && form.getParameters().get("id") != null) {
- _tmp_id = _tmp_id + form.getParameters().get("id").toString() + "_";
+ _tmp_id = _tmp_id.append(((TagAttribute)form.getParameters().get("id")).getValue() + "_");
}
if (name != null) {
- _tmp_id = _tmp_id + escape(name);
+ _tmp_id = _tmp_id.append(escape(name));
} else if (action != null || method != null){
if (action != null) {
- _tmp_id = _tmp_id + escape(action);
+ _tmp_id = _tmp_id.append(escape(action));
}
if (method != null) {
- _tmp_id = _tmp_id + "_" + escape(method);
+ _tmp_id = _tmp_id.append("_" + escape(method));
}
} else {
// if form is null, this component is used, without a form, i guess
// there's not much we could do then.
if (form != null) {
- _tmp_id = _tmp_id + form.getSequence();
+ _tmp_id = _tmp_id.append(String.valueOf(form.getSequence()));
}
}
}
+ this.id = _tmp_id;
addParameter("id", _tmp_id);
}
diff --git a/core/src/main/java/org/apache/struts2/components/ServletUrlRenderer.java b/core/src/main/java/org/apache/struts2/components/ServletUrlRenderer.java
index b8b7a3c..db7ca58 100644
--- a/core/src/main/java/org/apache/struts2/components/ServletUrlRenderer.java
+++ b/core/src/main/java/org/apache/struts2/components/ServletUrlRenderer.java
@@ -29,6 +29,7 @@ import org.apache.logging.log4j.Logger;
import org.apache.struts2.StrutsException;
import org.apache.struts2.dispatcher.mapper.ActionMapper;
import org.apache.struts2.dispatcher.mapper.ActionMapping;
+import org.apache.struts2.views.TagAttribute;
import org.apache.struts2.views.util.UrlHelper;
import java.io.IOException;
@@ -186,8 +187,9 @@ public class ServletUrlRenderer implements UrlRenderer {
}
// if the id isn't specified, use the action name
- if (formComponent.getId() == null && actionName != null) {
- formComponent.addParameter("id", formComponent.escape(actionName));
+ TagAttribute id = formComponent.getId();
+ if (id.isNull() && actionName != null) {
+ formComponent.addParameter("id", TagAttribute.evaluated(actionName).escaped());
}
} else if (action != null) {
// Since we can't find an action alias in the configuration, we just
@@ -213,16 +215,16 @@ public class ServletUrlRenderer implements UrlRenderer {
// name/id: cut out anything between / and . should be the id and
// name
- String id = formComponent.getId();
- if (id == null) {
+ TagAttribute id = formComponent.getId();
+ if (id == null || id.isNull()) {
slash = result.lastIndexOf('/');
int dot = result.indexOf('.', slash);
if (dot != -1) {
- id = result.substring(slash + 1, dot);
+ id = TagAttribute.evaluated(result.substring(slash + 1, dot));
} else {
- id = result.substring(slash + 1);
+ id = TagAttribute.evaluated(result.substring(slash + 1));
}
- formComponent.addParameter("id", formComponent.escape(id));
+ formComponent.addParameter("id", id.escaped());
}
}
diff --git a/core/src/main/java/org/apache/struts2/components/UIBean.java b/core/src/main/java/org/apache/struts2/components/UIBean.java
index 0e44a3b..4ca5c00 100644
--- a/core/src/main/java/org/apache/struts2/components/UIBean.java
+++ b/core/src/main/java/org/apache/struts2/components/UIBean.java
@@ -31,6 +31,7 @@ import org.apache.struts2.components.template.TemplateEngine;
import org.apache.struts2.components.template.TemplateEngineManager;
import org.apache.struts2.components.template.TemplateRenderingContext;
import org.apache.struts2.util.TextProviderHelper;
+import org.apache.struts2.views.TagAttribute;
import org.apache.struts2.views.annotations.StrutsTagAttribute;
import org.apache.struts2.views.util.ContextUtil;
@@ -456,7 +457,7 @@ public abstract class UIBean extends Component {
// shortcut, sets label, name, and value
protected String key;
- protected String id;
+ protected TagAttribute id = TagAttribute.NULL;
protected String cssClass;
protected String cssStyle;
protected String cssErrorClass;
@@ -989,25 +990,26 @@ public abstract class UIBean extends Component {
* @param form enclosing form tag
*/
protected void populateComponentHtmlId(Form form) {
- String tryId;
+ TagAttribute tryId;
String generatedId;
- if (id != null) {
+ if (id != null && !id.isNull()) {
// this check is needed for backwards compatibility with 2.1.x
tryId = findStringIfAltSyntax(id);
} else if (null == (generatedId = escape(name != null ? findString(name) : null))) {
LOG.debug("Cannot determine id attribute for [{}], consider defining id, name or key attribute!", this);
- tryId = null;
+ tryId = TagAttribute.NULL;
} else if (form != null) {
- tryId = form.getParameters().get("id") + "_" + generatedId;
+ tryId = TagAttribute.evaluated(((TagAttribute)form.getParameters().get("id")).getValue() + "_" + generatedId);
} else {
- tryId = generatedId;
+ tryId = TagAttribute.evaluated(generatedId);
}
//fix for https://issues.apache.org/jira/browse/WW-4299
//do not assign value to id if tryId is null
- if (tryId != null) {
- addParameter("id", tryId);
- addParameter("escapedId", escape(tryId));
+ if (!tryId.isNull()) {
+ id = tryId;
+ addParameter("id", tryId);
+ addParameter("escapedId", tryId.escaped());
}
}
@@ -1015,15 +1017,13 @@ public abstract class UIBean extends Component {
* Get's the id for referencing element.
* @return the id for referencing element.
*/
- public String getId() {
+ public TagAttribute getId() {
return id;
}
@StrutsTagAttribute(description="HTML id attribute")
public void setId(String id) {
- if (id != null) {
- this.id = findString(id);
- }
+ this.id = TagAttribute.raw(id);
}
@StrutsTagAttribute(description="The template directory.")
diff --git a/core/src/main/java/org/apache/struts2/views/TagAttribute.java b/core/src/main/java/org/apache/struts2/views/TagAttribute.java
new file mode 100644
index 0000000..42daa38
--- /dev/null
+++ b/core/src/main/java/org/apache/struts2/views/TagAttribute.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.struts2.views;
+
+public class TagAttribute {
+
+ public static final TagAttribute NULL = new TagAttribute(null, true);
+ public static final TagAttribute EMPTY = new TagAttribute("", true);
+
+ private final String value;
+ private final boolean evaluated;
+
+ private TagAttribute(String value, boolean evaluated) {
+ this.value = value;
+ this.evaluated = evaluated;
+ }
+
+ public static TagAttribute raw(String value) {
+ return new TagAttribute(value, false);
+ }
+
+ public static TagAttribute evaluated(String evaluatedValue) {
+ return new TagAttribute(evaluatedValue, true);
+ }
+
+ public boolean isExpression() {
+ return value != null && value.contains("%{") && value.contains("}");
+ }
+
+ public String stripedExpression() {
+ if (isExpression()) {
+ return value.substring(2, value.length() - 1);
+ } else {
+ return value;
+ }
+ }
+
+ public TagAttribute escaped(){
+ // escape any possible values that can make the ID painful to work with in JavaScript
+ if (value != null) {
+ return TagAttribute.evaluated(value.replaceAll("[\\/\\.\\[\\]\'\"]", "_"));
+ } else {
+ return null;
+ }
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public boolean isEvaluated() {
+ return evaluated;
+ }
+
+ public boolean isNull() {
+ return value == null;
+ }
+
+ public TagAttribute append(String appendString) {
+ return TagAttribute.evaluated(value + appendString);
+ }
+
+}
diff --git a/core/src/main/java/org/apache/struts2/views/freemarker/StrutsBeanWrapper.java b/core/src/main/java/org/apache/struts2/views/freemarker/StrutsBeanWrapper.java
index 3f94f96..dc038ce 100644
--- a/core/src/main/java/org/apache/struts2/views/freemarker/StrutsBeanWrapper.java
+++ b/core/src/main/java/org/apache/struts2/views/freemarker/StrutsBeanWrapper.java
@@ -30,7 +30,9 @@ import freemarker.template.SimpleSequence;
import freemarker.template.TemplateCollectionModel;
import freemarker.template.TemplateHashModelEx;
import freemarker.template.TemplateModel;
+import freemarker.template.TemplateModelException;
import freemarker.template.Version;
+import org.apache.struts2.views.TagAttribute;
/**
* <!-- START SNIPPET: javadoc -->
@@ -49,7 +51,8 @@ import freemarker.template.Version;
* <!-- END SNIPPET: javadoc -->
*/
public class StrutsBeanWrapper extends BeansWrapper {
- private boolean altMapWrapper;
+
+ private final boolean altMapWrapper;
public StrutsBeanWrapper(boolean altMapWrapper, Version incompatibleImprovements) {
super(incompatibleImprovements);
@@ -65,6 +68,16 @@ public class StrutsBeanWrapper extends BeansWrapper {
return super.getModelFactory(clazz);
}
+ @Override
+ public TemplateModel wrap(final Object obj) throws TemplateModelException {
+ if (obj instanceof TagAttribute) {
+ TagAttribute attribute = (TagAttribute) obj;
+ return new TagAttributeAdapter(attribute, this);
+ }
+
+ return super.wrap(obj);
+ }
+
/**
* Attempting to get the best of both worlds of FM's MapModel and SimpleMapModel, by reimplementing the isEmpty(),
* keySet() and values() methods. ?keys and ?values built-ins are thus available, just as well as plain Map
diff --git a/core/src/main/java/org/apache/struts2/views/freemarker/TagAttributeAdapter.java b/core/src/main/java/org/apache/struts2/views/freemarker/TagAttributeAdapter.java
new file mode 100644
index 0000000..81686a5
--- /dev/null
+++ b/core/src/main/java/org/apache/struts2/views/freemarker/TagAttributeAdapter.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.struts2.views.freemarker;
+
+import freemarker.template.AdapterTemplateModel;
+import freemarker.template.ObjectWrapper;
+import freemarker.template.TemplateModelException;
+import freemarker.template.TemplateScalarModel;
+import freemarker.template.WrappingTemplateModel;
+import org.apache.struts2.views.TagAttribute;
+
+public class TagAttributeAdapter extends WrappingTemplateModel implements AdapterTemplateModel, TemplateScalarModel {
+
+ private final TagAttribute attribute;
+
+ public TagAttributeAdapter(TagAttribute attribute, ObjectWrapper ow) {
+ super(ow);
+ this.attribute = attribute;
+ }
+
+ @Override
+ public Object getAdaptedObject(Class<?> hint) {
+ return attribute;
+ }
+
+ @Override
+ public String getAsString() throws TemplateModelException {
+ return attribute.getValue();
+ }
+
+}
diff --git a/core/src/test/java/org/apache/struts2/components/FormButtonTest.java b/core/src/test/java/org/apache/struts2/components/FormButtonTest.java
index bf0fe95..2620542 100644
--- a/core/src/test/java/org/apache/struts2/components/FormButtonTest.java
+++ b/core/src/test/java/org/apache/struts2/components/FormButtonTest.java
@@ -19,6 +19,7 @@
package org.apache.struts2.components;
import org.apache.struts2.StrutsInternalTestCase;
+import org.apache.struts2.views.TagAttribute;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
@@ -31,7 +32,7 @@ import com.opensymphony.xwork2.util.ValueStack;
*/
public class FormButtonTest extends StrutsInternalTestCase {
- public void testPopulateComponentHtmlId1() throws Exception {
+ public void testPopulateComponentHtmlId1() {
MockHttpServletRequest req = new MockHttpServletRequest();
MockHttpServletResponse res = new MockHttpServletResponse();
ValueStack stack = ActionContext.getContext().getValueStack();
@@ -44,32 +45,32 @@ public class FormButtonTest extends StrutsInternalTestCase {
submit.populateComponentHtmlId(form);
- assertEquals("submitId", submit.getParameters().get("id"));
+ assertEquals("submitId", submit.getId().getValue());
}
- public void testPopulateComponentHtmlId2() throws Exception {
+ public void testPopulateComponentHtmlId2() {
MockHttpServletRequest req = new MockHttpServletRequest();
MockHttpServletResponse res = new MockHttpServletResponse();
ValueStack stack = ActionContext.getContext().getValueStack();
Form form = new Form(stack, req, res);
- form.getParameters().put("id", "formId");
+ form.getParameters().put("id", TagAttribute.evaluated("formId"));
Submit submit = new Submit(stack, req, res);
submit.setName("submitName");
submit.populateComponentHtmlId(form);
- assertEquals("formId_submitName", submit.getParameters().get("id"));
+ assertEquals("formId_submitName", submit.getId().getValue());
}
- public void testPopulateComponentHtmlId3() throws Exception {
+ public void testPopulateComponentHtmlId3() {
MockHttpServletRequest req = new MockHttpServletRequest();
MockHttpServletResponse res = new MockHttpServletResponse();
ValueStack stack = ActionContext.getContext().getValueStack();
Form form = new Form(stack, req, res);
- form.getParameters().put("id", "formId");
+ form.getParameters().put("id", TagAttribute.evaluated("formId"));
Submit submit = new Submit(stack, req, res);
submit.setAction("submitAction");
@@ -77,10 +78,10 @@ public class FormButtonTest extends StrutsInternalTestCase {
submit.populateComponentHtmlId(form);
- assertEquals("formId_submitAction_submitMethod", submit.getParameters().get("id"));
+ assertEquals("formId_submitAction_submitMethod", submit.getId().getValue());
}
- public void testPopulateComponentHtmlId4() throws Exception {
+ public void testPopulateComponentHtmlId4() {
MockHttpServletRequest req = new MockHttpServletRequest();
MockHttpServletResponse res = new MockHttpServletResponse();
ValueStack stack = ActionContext.getContext().getValueStack();
@@ -90,10 +91,10 @@ public class FormButtonTest extends StrutsInternalTestCase {
submit.populateComponentHtmlId(null);
- assertEquals("submitId", submit.getParameters().get("id"));
+ assertEquals("submitId", submit.getId().getValue());
}
- public void testPopulateComponentHtmlId5() throws Exception {
+ public void testPopulateComponentHtmlId5() {
MockHttpServletRequest req = new MockHttpServletRequest();
MockHttpServletResponse res = new MockHttpServletResponse();
ValueStack stack = ActionContext.getContext().getValueStack();
@@ -103,10 +104,10 @@ public class FormButtonTest extends StrutsInternalTestCase {
submit.populateComponentHtmlId(null);
- assertEquals("submitName", submit.getParameters().get("id"));
+ assertEquals("submitName", submit.getId().getValue());
}
- public void testPopulateComponentHtmlId6() throws Exception {
+ public void testPopulateComponentHtmlId6() {
MockHttpServletRequest req = new MockHttpServletRequest();
MockHttpServletResponse res = new MockHttpServletResponse();
ValueStack stack = ActionContext.getContext().getValueStack();
@@ -117,6 +118,6 @@ public class FormButtonTest extends StrutsInternalTestCase {
submit.populateComponentHtmlId(null);
- assertEquals("submitAction_submitMethod", submit.getParameters().get("id"));
+ assertEquals("submitAction_submitMethod", submit.getId().getValue());
}
}
diff --git a/core/src/test/java/org/apache/struts2/components/UIBeanTest.java b/core/src/test/java/org/apache/struts2/components/UIBeanTest.java
index 9317397..5977f3a 100644
--- a/core/src/test/java/org/apache/struts2/components/UIBeanTest.java
+++ b/core/src/test/java/org/apache/struts2/components/UIBeanTest.java
@@ -25,6 +25,7 @@ import org.apache.struts2.StrutsInternalTestCase;
import org.apache.struts2.components.template.Template;
import org.apache.struts2.components.template.TemplateEngine;
import org.apache.struts2.components.template.TemplateEngineManager;
+import org.apache.struts2.views.TagAttribute;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
@@ -40,14 +41,14 @@ public class UIBeanTest extends StrutsInternalTestCase {
MockHttpServletResponse res = new MockHttpServletResponse();
Form form = new Form(stack, req, res);
- form.getParameters().put("id", "formId");
+ form.getParameters().put("id", TagAttribute.evaluated("formId"));
TextField txtFld = new TextField(stack, req, res);
txtFld.setId("txtFldId");
txtFld.populateComponentHtmlId(form);
- assertEquals("txtFldId", txtFld.getParameters().get("id"));
+ assertEquals("txtFldId", txtFld.getId().getValue());
}
public void testPopulateComponentHtmlIdWithOgnl() throws Exception {
@@ -56,14 +57,14 @@ public class UIBeanTest extends StrutsInternalTestCase {
MockHttpServletResponse res = new MockHttpServletResponse();
Form form = new Form(stack, req, res);
- form.getParameters().put("id", "formId");
+ form.getParameters().put("id", TagAttribute.evaluated("formId"));
TextField txtFld = new TextField(stack, req, res);
txtFld.setName("txtFldName%{'1'}");
txtFld.populateComponentHtmlId(form);
- assertEquals("formId_txtFldName1", txtFld.getParameters().get("id"));
+ assertEquals("formId_txtFldName1", txtFld.getId().getValue());
}
public void testPopulateComponentHtmlId2() throws Exception {
@@ -72,14 +73,14 @@ public class UIBeanTest extends StrutsInternalTestCase {
MockHttpServletResponse res = new MockHttpServletResponse();
Form form = new Form(stack, req, res);
- form.getParameters().put("id", "formId");
+ form.getParameters().put("id", TagAttribute.evaluated("formId"));
TextField txtFld = new TextField(stack, req, res);
txtFld.setName("txtFldName");
txtFld.populateComponentHtmlId(form);
- assertEquals("formId_txtFldName", txtFld.getParameters().get("id"));
+ assertEquals("formId_txtFldName", txtFld.getId().getValue());
}
public void testPopulateComponentHtmlWithoutNameAndId() throws Exception {
@@ -94,7 +95,7 @@ public class UIBeanTest extends StrutsInternalTestCase {
txtFld.populateComponentHtmlId(form);
- assertEquals(null, txtFld.getParameters().get("id"));
+ assertNull(txtFld.getParameters().get("id"));
}
public void testEscape() throws Exception {
@@ -120,12 +121,12 @@ public class UIBeanTest extends StrutsInternalTestCase {
MockHttpServletResponse res = new MockHttpServletResponse();
Form form = new Form(stack, req, res);
- form.getParameters().put("id", "formId");
+ form.getParameters().put("id", TagAttribute.evaluated("formId"));
TextField txtFld = new TextField(stack, req, res);
txtFld.setName("foo/bar");
txtFld.populateComponentHtmlId(form);
- assertEquals("formId_foo_bar", txtFld.getParameters().get("id"));
+ assertEquals("formId_foo_bar", txtFld.getId().getValue());
}
public void testGetThemeFromForm() throws Exception {
diff --git a/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/Attributes.java b/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/Attributes.java
index 3a60507..5e6f370 100644
--- a/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/Attributes.java
+++ b/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/Attributes.java
@@ -20,6 +20,7 @@ package org.apache.struts2.views.java;
import org.apache.commons.text.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
+import org.apache.struts2.views.TagAttribute;
import java.util.LinkedHashMap;
@@ -60,6 +61,9 @@ public class Attributes extends LinkedHashMap<String, String> {
public Attributes addIfExists(String attrName, Object paramValue, boolean encode) {
if (paramValue != null) {
String val = paramValue.toString();
+ if (paramValue instanceof TagAttribute) {
+ val = ((TagAttribute) paramValue).getValue();
+ }
if (StringUtils.isNotBlank(val))
put(attrName, (encode ? StringUtils.defaultString(StringEscapeUtils.escapeHtml4(val)) : val));
}
diff --git a/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/simple/CheckboxHandler.java b/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/simple/CheckboxHandler.java
index c712dda..f01794c 100644
--- a/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/simple/CheckboxHandler.java
+++ b/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/simple/CheckboxHandler.java
@@ -18,6 +18,7 @@
*/
package org.apache.struts2.views.java.simple;
+import org.apache.struts2.views.TagAttribute;
import org.apache.struts2.views.java.Attributes;
import org.apache.struts2.views.java.TagGenerator;
import org.apache.commons.lang3.StringUtils;
@@ -32,7 +33,7 @@ public class CheckboxHandler extends AbstractTagHandler implements TagGenerator
Attributes attrs = new Attributes();
String fieldValue = (String) params.get("fieldValue");
- String id = (String) params.get("id");
+ TagAttribute id = (TagAttribute) params.get("id");
String name = (String) params.get("name");
Object disabled = params.get("disabled");
@@ -52,8 +53,9 @@ public class CheckboxHandler extends AbstractTagHandler implements TagGenerator
//hidden input
attrs = new Attributes();
+ String idStr = id != null ? id.getValue() : null;
attrs.add("type", "hidden")
- .add("id", "__checkbox_" + StringUtils.defaultString(StringEscapeUtils.escapeHtml4(id)))
+ .add("id", "__checkbox_" + StringUtils.defaultString(StringEscapeUtils.escapeHtml4(idStr)))
.add("name", "__checkbox_" + StringUtils.defaultString(StringEscapeUtils.escapeHtml4(name)))
.add("value", "__checkbox_" + StringUtils.defaultString(StringEscapeUtils.escapeHtml4(fieldValue)))
.addIfTrue("disabled", disabled);
diff --git a/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/simple/DateTextFieldHandler.java b/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/simple/DateTextFieldHandler.java
index 7c93a6b..91963ba 100644
--- a/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/simple/DateTextFieldHandler.java
+++ b/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/simple/DateTextFieldHandler.java
@@ -24,6 +24,7 @@ import java.util.Date;
import java.util.Map;
import org.apache.struts2.interceptor.DateTextFieldInterceptor.DateWord;
+import org.apache.struts2.views.TagAttribute;
import org.apache.struts2.views.java.Attributes;
import org.apache.struts2.views.java.TagGenerator;
@@ -37,7 +38,7 @@ public class DateTextFieldHandler extends AbstractTagHandler implements TagGener
// Get format
String format = (String)params.get("format");
- String id = (String)params.get("id");
+ String id = params.get("id") != null ? ((TagAttribute) params.get("id")).getValue() : null;
String name = (String)params.get("name");
if (id == null) {
id = name;
diff --git a/plugins/portlet/src/main/java/org/apache/struts2/components/PortletUrlRenderer.java b/plugins/portlet/src/main/java/org/apache/struts2/components/PortletUrlRenderer.java
index 4b51f7e..4783581 100644
--- a/plugins/portlet/src/main/java/org/apache/struts2/components/PortletUrlRenderer.java
+++ b/plugins/portlet/src/main/java/org/apache/struts2/components/PortletUrlRenderer.java
@@ -18,7 +18,6 @@
*/
package org.apache.struts2.components;
-import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.inject.Inject;
import org.apache.commons.lang3.StringUtils;
@@ -27,6 +26,7 @@ import org.apache.struts2.dispatcher.mapper.ActionMapper;
import org.apache.struts2.portlet.context.PortletActionContext;
import org.apache.struts2.portlet.util.PortletUrlHelper;
import org.apache.struts2.portlet.util.PortletUrlHelperJSR286;
+import org.apache.struts2.views.TagAttribute;
import org.apache.struts2.views.util.UrlHelper;
import javax.portlet.PortletMode;
@@ -183,16 +183,16 @@ public class PortletUrlRenderer implements UrlRenderer {
// name/id: cut out anything between / and . should be the id and
// name
- String id = formComponent.getId();
- if (id == null) {
+ TagAttribute id = formComponent.getId();
+ if (id.isNull()) {
int slash = action.lastIndexOf('/');
int dot = action.indexOf('.', slash);
if (dot != -1) {
- id = action.substring(slash + 1, dot);
+ id = TagAttribute.evaluated(action.substring(slash + 1, dot));
} else {
- id = action.substring(slash + 1);
+ id = TagAttribute.evaluated(action.substring(slash + 1));
}
- formComponent.addParameter("id", formComponent.escape(id));
+ formComponent.addParameter("id", id.escaped());
}
}
}