This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch WW-5782-anchor-href-params
in repository https://gitbox.apache.org/repos/asf/struts.git

commit c58dfad3914c201665b9f2425a56d709c37adf2d
Author: Lukasz Lenart <[email protected]>
AuthorDate: Fri Oct 16 11:27:54 2026 +0200

    WW-5782 fix(tags): document and warn that s:a href ignores nested params
    
    With an explicit href the anchor tag never applies nested <s:param> tags;
    they are only used when the URL is built from value or action. The javadoc
    example showed exactly that combination.
    
    The example now uses value, the javadoc and the href attribute description
    say nested params are not applied to href, and in devMode the tag logs a
    warning naming the ignored params. Rendered output is unchanged; applying
    params to href is WW-5783 (8.0.0).
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
 .../java/org/apache/struts2/components/Anchor.java | 11 +++--
 core/src/site/resources/tags/a-attributes.html     |  2 +-
 .../apache/struts2/views/jsp/AnchorTagTest.java    | 50 ++++++++++++++++++++++
 3 files changed, 59 insertions(+), 4 deletions(-)

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 6bda43f20..9e7e09fc7 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 @@ import java.util.Map;
  * <!-- START SNIPPET: javadoc -->
  * <p>
  * A tag that creates a HTML &lt;a &gt;.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.
  * </p>
  * <!-- END SNIPPET: javadoc -->
  *
@@ -46,7 +47,7 @@ import java.util.Map;
  *
  * <pre>
  * <!-- START SNIPPET: example1 -->
- * &lt;s:a id="link1" href="/do-it.action"&gt;
+ * &lt;s:a id="link1" value="/do-it.action"&gt;
  *     &lt;img border="none" 
src="&lt;%=request.getContextPath()%&gt;/images/delete.gif"/&gt;
  *     &lt;s:param name="id" value="1"/&gt;
  * &lt;/s:a&gt;
@@ -101,6 +102,10 @@ public class Anchor extends ClosingUIBean {
 
         if (href != null) {
             addParameter("href", 
ensureAttributeSafelyNotEscaped(findString(href)));
+            if (devMode && !urlParameters.isEmpty()) {
+                LOG.warn("Nested params {} are ignored because <s:a> 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 class Anchor extends ClosingUIBean {
         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 48ba23f96..738d0bc36 100644
--- a/core/src/site/resources/tags/a-attributes.html
+++ b/core/src/site/resources/tags/a-attributes.html
@@ -123,7 +123,7 @@
         <td class="tag-attribute"></td>
         <td class="tag-attribute">false</td>
         <td class="tag-attribute">String</td>
-        <td class="tag-attribute">The URL.</td>
+        <td class="tag-attribute">The URL. Nested param tags are not applied, 
use value or action to build a URL with params</td>
     </tr>
     <tr>
         <td class="tag-attribute">id</td>
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 7bf07bd68..1b9047a2b 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 @@ public class AnchorTagTest extends AbstractUITagTest {
         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();
+    }
+
 }

Reply via email to