diff --git a/core/src/main/java/org/apache/struts2/components/Anchor.java b/core/src/main/java/org/apache/struts2/components/Anchor.java index 6bda43f209..9e7e09fc7a 100644 --- a/core/src/main/java/org/apache/struts2/components/Anchor.java +++ b/core/src/main/java/org/apache/struts2/components/Anchor.java @@ -38,7 +38,8 @@ * *

* A tag that creates a HTML <a >.This tag supports the same attributes as the "url" tag, - * including nested parameters using the "param" tag. + * including nested parameters using the "param" tag. Nested parameters are applied only when the URL is built + * from the "value" or "action" attributes; they are ignored when "href" is set. *

* * @@ -46,7 +47,7 @@ * *
  * 
- * <s:a id="link1" href="/do-it.action">
+ * <s:a id="link1" value="/do-it.action">
  *     <img border="none" src="<%=request.getContextPath()%>/images/delete.gif"/>
  *     <s:param name="id" value="1"/>
  * </s:a>
@@ -101,6 +102,10 @@ protected void evaluateExtraParams() {
 
         if (href != null) {
             addParameter("href", ensureAttributeSafelyNotEscaped(findString(href)));
+            if (devMode && !urlParameters.isEmpty()) {
+                LOG.warn("Nested params {} are ignored because  has href [{}], use value or action to build a URL with params",
+                        urlParameters.keySet(), href);
+            }
         } else {
             //no href, build it from URL attributes
             StringWriter sw = new StringWriter();
@@ -189,7 +194,7 @@ public UrlProvider getUrlProvider() {
         return urlProvider;
     }
 
-    @StrutsTagAttribute(description = "The URL.")
+    @StrutsTagAttribute(description = "The URL. Nested param tags are not applied, use value or action to build a URL with params")
     public void setHref(String href) {
         this.href = href;
     }
diff --git a/core/src/site/resources/tags/a-attributes.html b/core/src/site/resources/tags/a-attributes.html
index 48ba23f962..738d0bc369 100644
--- a/core/src/site/resources/tags/a-attributes.html
+++ b/core/src/site/resources/tags/a-attributes.html
@@ -123,7 +123,7 @@
         
         false
         String
-        The URL.
+        The URL. Nested param tags are not applied, use value or action to build a URL with params
     
     
         id
diff --git a/core/src/test/java/org/apache/struts2/views/jsp/AnchorTagTest.java b/core/src/test/java/org/apache/struts2/views/jsp/AnchorTagTest.java
index 7bf07bd686..1b9047a2b8 100644
--- a/core/src/test/java/org/apache/struts2/views/jsp/AnchorTagTest.java
+++ b/core/src/test/java/org/apache/struts2/views/jsp/AnchorTagTest.java
@@ -18,6 +18,8 @@
  */
 package org.apache.struts2.views.jsp;
 
+import org.apache.struts2.components.Anchor;
+import org.apache.struts2.test.LogCapture;
 import org.apache.struts2.views.jsp.ui.AnchorTag;
 import org.apache.struts2.views.jsp.ui.StrutsBodyContent;
 
@@ -1646,4 +1648,52 @@ protected void setUp() throws Exception {
         pageContext.setJspWriter(jspWriter);
     }
 
+    public void testHrefIgnoresNestedParams() throws Exception {
+        tag.setHref("/do-it.action");
+
+        try (LogCapture logs = new LogCapture(Anchor.class)) {
+            renderWithParam("id", "%{'1'}");
+
+            assertEquals(wrapWithAnchor("/do-it.action"), writer.toString());
+            assertTrue(logs.messages().toString(), logs.messages().isEmpty());
+        }
+    }
+
+    public void testHrefWithNestedParamsWarnsInDevMode() throws Exception {
+        setDevMode(true);
+        tag.setHref("/do-it.action");
+
+        try (LogCapture logs = new LogCapture(Anchor.class)) {
+            renderWithParam("id", "%{'1'}");
+
+            assertEquals(wrapWithAnchor("/do-it.action"), writer.toString());
+            assertEquals(1, logs.messages().size());
+            assertTrue(logs.messages().get(0), logs.messages().get(0).contains("[id]"));
+        }
+    }
+
+    public void testValueWithNestedParamsDoesNotWarnInDevMode() throws Exception {
+        setDevMode(true);
+        tag.setValue("/do-it.action");
+
+        try (LogCapture logs = new LogCapture(Anchor.class)) {
+            renderWithParam("id", "%{'1'}");
+
+            assertEquals(wrapWithAnchor("/do-it.action?id=1"), writer.toString());
+            assertTrue(logs.messages().toString(), logs.messages().isEmpty());
+        }
+    }
+
+    private void renderWithParam(String name, String value) throws JspException {
+        ParamTag param = new ParamTag();
+        param.setPageContext(pageContext);
+        param.setName(name);
+        param.setValue(value);
+
+        tag.doStartTag();
+        param.doStartTag();
+        param.doEndTag();
+        tag.doEndTag();
+    }
+
 }