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

lukaszlenart pushed a commit to branch WW-3871-typeconversion-key-derivation
in repository https://gitbox.apache.org/repos/asf/struts.git

commit af603fa692841ae593bb846dbb24217f25aeba6b
Author: Lukasz Lenart <[email protected]>
AuthorDate: Sat Jul 25 15:38:59 2026 +0200

    WW-3871 test(core): assert bare conversion keys bind through the action 
lifecycle
    
    Co-Authored-By: Claude Opus 5 <[email protected]>
---
 .../org/apache/struts2/util/MyBeanActionTest.java  | 25 ++++++++
 .../apache/struts2/util/MyBeanBareKeyAction.java   | 68 ++++++++++++++++++++++
 core/src/test/resources/xwork-sample.xml           |  6 ++
 3 files changed, 99 insertions(+)

diff --git a/core/src/test/java/org/apache/struts2/util/MyBeanActionTest.java 
b/core/src/test/java/org/apache/struts2/util/MyBeanActionTest.java
index 98c836d5b..3f19efbfe 100644
--- a/core/src/test/java/org/apache/struts2/util/MyBeanActionTest.java
+++ b/core/src/test/java/org/apache/struts2/util/MyBeanActionTest.java
@@ -126,6 +126,31 @@ public class MyBeanActionTest extends XWorkTestCase {
         }
     }
 
+    public void testBareConversionKeysBindTheSameWayAsPrefixedOnes() throws 
Exception {
+        HashMap<String, Object> params = new HashMap<>();
+        params.put("annotatedBeanList(1234567890).name", "This is the bla bean 
by annotation");
+        params.put("annotatedBeanMap[1234567891].id", "1234567891");
+        params.put("annotatedBeanMap[1234567891].name", "This is the 2nd bla 
bean by annotation");
+
+        ActionContext extraContext = 
ActionContext.of().withParameters(HttpParameters.create(params).build());
+
+        ActionProxy proxy = actionProxyFactory.createActionProxy("", 
"MyBeanBareKey", null, extraContext.getContextMap());
+        proxy.execute();
+        MyBeanBareKeyAction action = (MyBeanBareKeyAction) 
proxy.getInvocation().getAction();
+
+        // CreateIfNull_annotatedBeanList + Element_annotatedBeanList
+        assertEquals(1, action.getAnnotatedBeanList().size());
+        assertEquals(MyBean.class, 
action.getAnnotatedBeanList().get(0).getClass());
+        assertEquals("This is the bla bean by annotation",
+                
proxy.getInvocation().getStack().findValue("annotatedBeanList.get(0).name"));
+
+        // Key_annotatedBeanMap makes the key a Long, Element_annotatedBeanMap 
makes the value a MyBean
+        assertTrue(action.getAnnotatedBeanMap().containsKey(1234567891L));
+        assertEquals(MyBean.class, 
action.getAnnotatedBeanMap().get(1234567891L).getClass());
+        assertEquals("This is the 2nd bla bean by annotation",
+                
proxy.getInvocation().getStack().findValue("annotatedBeanMap.get(1234567891L).name"));
+    }
+
     @Override
     protected void setUp() throws Exception {
         super.setUp();
diff --git 
a/core/src/test/java/org/apache/struts2/util/MyBeanBareKeyAction.java 
b/core/src/test/java/org/apache/struts2/util/MyBeanBareKeyAction.java
new file mode 100644
index 000000000..ebc232f03
--- /dev/null
+++ b/core/src/test/java/org/apache/struts2/util/MyBeanBareKeyAction.java
@@ -0,0 +1,68 @@
+/*
+ * 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.util;
+
+import org.apache.struts2.action.Action;
+import org.apache.struts2.conversion.annotations.Conversion;
+import org.apache.struts2.conversion.annotations.ConversionRule;
+import org.apache.struts2.conversion.annotations.TypeConversion;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * {@link MyBeanAction} restated with bare property names as conversion keys. 
Both must bind
+ * identically; {@code MyBeanAction} keeps the spelled-out prefixes so the old 
form stays covered.
+ */
+@Conversion(
+        conversions = {
+                @TypeConversion(key = "annotatedBeanMap", rule = 
ConversionRule.KEY_PROPERTY, value = "id"),
+                @TypeConversion(key = "annotatedBeanMap", rule = 
ConversionRule.ELEMENT, converterClass = MyBean.class),
+                @TypeConversion(key = "annotatedBeanList", rule = 
ConversionRule.KEY_PROPERTY, value = "id"),
+                @TypeConversion(key = "annotatedBeanList", rule = 
ConversionRule.ELEMENT, converterClass = MyBean.class)
+        })
+public class MyBeanBareKeyAction implements Action {
+
+    private Map annotatedBeanMap = new HashMap();
+    private List annotatedBeanList = new ArrayList();
+
+    public Map getAnnotatedBeanMap() {
+        return annotatedBeanMap;
+    }
+
+    @TypeConversion(rule = ConversionRule.KEY, converterClass = Long.class)
+    public void setAnnotatedBeanMap(Map annotatedBeanMap) {
+        this.annotatedBeanMap = annotatedBeanMap;
+    }
+
+    public List getAnnotatedBeanList() {
+        return annotatedBeanList;
+    }
+
+    @TypeConversion(rule = ConversionRule.CREATE_IF_NULL, value = "true")
+    public void setAnnotatedBeanList(List annotatedBeanList) {
+        this.annotatedBeanList = annotatedBeanList;
+    }
+
+    public String execute() throws Exception {
+        return SUCCESS;
+    }
+}
diff --git a/core/src/test/resources/xwork-sample.xml 
b/core/src/test/resources/xwork-sample.xml
index 5bc189d82..456dc6dad 100644
--- a/core/src/test/resources/xwork-sample.xml
+++ b/core/src/test/resources/xwork-sample.xml
@@ -131,6 +131,12 @@
             <result name="success" type="mock"/>
         </action>
 
+        <action name="MyBeanBareKey" 
class="org.apache.struts2.util.MyBeanBareKeyAction">
+            <interceptor-ref name="debugStack"/>
+            <interceptor-ref name="defaultStack"/>
+            <result name="success" type="mock"/>
+        </action>
+
         <action name="TestInterceptorParam" 
class="org.apache.struts2.SimpleAction">
             <interceptor-ref name="test">
                 <param name="expectedFoo">expectedFoo</param>

Reply via email to