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>
