From 0b2bc2be1420829dfd26356dd8ea906a793c8047 Mon Sep 17 00:00:00 2001 From: Lukasz Lenart Date: Sun, 26 Jul 2026 10:33:09 +0200 Subject: [PATCH] WW-3427 Add regression test for conversion errors on aliased properties (#1814) * WW-3427 test(core): cover conversion errors on aliased properties Reproduce the WW-3427 scenario: an aliased property whose custom TypeConverter throws TypeConversionException. AliasInterceptor already reports such errors (setReportingConversionErrors on the secure child stack, then copies conversion errors back to the original ActionContext), but nothing exercised the alias + conversion-error path. The test drives an action through params -> alias -> conversionError and asserts the failure surfaces both in ActionContext.getConversionErrors() and as a field error, confirming WW-3427 is fixed. Removing the copy-back in AliasInterceptor makes it fail with "swallowed", proving it guards the behavior. Test-only; no production changes. Co-Authored-By: Claude Opus 4.8 * WW-3427 test(core): add Apache license header to conversion.properties RAT flagged the new test resource as having an unapproved license. Co-Authored-By: Claude Opus 4.8 --------- Co-authored-by: Claude Opus 4.8 --- .../interceptor/AliasConversionAction.java | 50 +++++++++++++++++++ .../interceptor/AliasInterceptorTest.java | 24 +++++++++ .../interceptor/ThrowingTypeConverter.java | 36 +++++++++++++ ...liasConversionAction-conversion.properties | 19 +++++++ .../test/resources/xwork-alias-conversion.xml | 44 ++++++++++++++++ 5 files changed, 173 insertions(+) create mode 100644 core/src/test/java/org/apache/struts2/interceptor/AliasConversionAction.java create mode 100644 core/src/test/java/org/apache/struts2/interceptor/ThrowingTypeConverter.java create mode 100644 core/src/test/resources/org/apache/struts2/interceptor/AliasConversionAction-conversion.properties create mode 100644 core/src/test/resources/xwork-alias-conversion.xml diff --git a/core/src/test/java/org/apache/struts2/interceptor/AliasConversionAction.java b/core/src/test/java/org/apache/struts2/interceptor/AliasConversionAction.java new file mode 100644 index 000000000..2588e5f4a --- /dev/null +++ b/core/src/test/java/org/apache/struts2/interceptor/AliasConversionAction.java @@ -0,0 +1,50 @@ +/* + * 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.interceptor; + +import org.apache.struts2.ActionSupport; + +import java.math.BigDecimal; + +/** + * Action fixture for WW-3427. The {@code aliasDest} property is bound through a custom + * {@link ThrowingTypeConverter} (registered via {@code AliasConversionAction-conversion.properties}), + * so aliasing a value onto it triggers a {@code TypeConversionException}. + */ +public class AliasConversionAction extends ActionSupport { + + private String aliasSource; + private BigDecimal aliasDest; + + public String getAliasSource() { + return aliasSource; + } + + public void setAliasSource(String aliasSource) { + this.aliasSource = aliasSource; + } + + public BigDecimal getAliasDest() { + return aliasDest; + } + + public void setAliasDest(BigDecimal aliasDest) { + this.aliasDest = aliasDest; + } +} diff --git a/core/src/test/java/org/apache/struts2/interceptor/AliasInterceptorTest.java b/core/src/test/java/org/apache/struts2/interceptor/AliasInterceptorTest.java index d2a38f332..39f2af3ea 100644 --- a/core/src/test/java/org/apache/struts2/interceptor/AliasInterceptorTest.java +++ b/core/src/test/java/org/apache/struts2/interceptor/AliasInterceptorTest.java @@ -77,6 +77,30 @@ public class AliasInterceptorTest extends XWorkTestCase { assertNull(actionOne.getBlah()); // WW-5087 } + // WW-3427: a conversion error thrown while binding an aliased property must not be swallowed; + // it must be reported through the ConversionErrorInterceptor / conversion errors, exactly as it + // would be for a non-aliased property. + public void testConversionErrorOnAliasedPropertyIsReported() throws Exception { + Map params = new HashMap<>(); + params.put("aliasSource", "not a number"); + + XmlConfigurationProvider provider = new StrutsXmlConfigurationProvider("xwork-alias-conversion.xml"); + container.inject(provider); + loadConfigurationProviders(provider); + + ActionProxy proxy = actionProxyFactory.createActionProxy("", "aliasConversionTest", null, params); + AliasConversionAction action = (AliasConversionAction) proxy.getAction(); + + proxy.execute(); + + // The custom converter throws TypeConversionException while setting the aliased 'aliasDest'. + assertTrue("conversion error for aliased property was swallowed", + proxy.getInvocation().getInvocationContext().getConversionErrors().containsKey("aliasDest")); + assertTrue("ConversionErrorInterceptor did not register a field error for the aliased property", + action.getFieldErrors().containsKey("aliasDest")); + assertNull("aliasDest must remain unset after a failed conversion", action.getAliasDest()); + } + public void testNameNotAccepted() throws Exception { Map params = new HashMap<>(); params.put("aliasSource", "source here"); diff --git a/core/src/test/java/org/apache/struts2/interceptor/ThrowingTypeConverter.java b/core/src/test/java/org/apache/struts2/interceptor/ThrowingTypeConverter.java new file mode 100644 index 000000000..2c0903870 --- /dev/null +++ b/core/src/test/java/org/apache/struts2/interceptor/ThrowingTypeConverter.java @@ -0,0 +1,36 @@ +/* + * 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.interceptor; + +import org.apache.struts2.conversion.TypeConversionException; +import org.apache.struts2.conversion.impl.DefaultTypeConverter; + +import java.util.Map; + +/** + * Test converter that always fails, used to reproduce WW-3427 (conversion errors on aliased + * properties must still be reported). + */ +public class ThrowingTypeConverter extends DefaultTypeConverter { + + @Override + public Object convertValue(Map context, Object value, Class toType) { + throw new TypeConversionException("intentional conversion failure for value: " + value); + } +} diff --git a/core/src/test/resources/org/apache/struts2/interceptor/AliasConversionAction-conversion.properties b/core/src/test/resources/org/apache/struts2/interceptor/AliasConversionAction-conversion.properties new file mode 100644 index 000000000..a3248285b --- /dev/null +++ b/core/src/test/resources/org/apache/struts2/interceptor/AliasConversionAction-conversion.properties @@ -0,0 +1,19 @@ +# +# 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. +# +aliasDest=org.apache.struts2.interceptor.ThrowingTypeConverter diff --git a/core/src/test/resources/xwork-alias-conversion.xml b/core/src/test/resources/xwork-alias-conversion.xml new file mode 100644 index 000000000..cb943e1fc --- /dev/null +++ b/core/src/test/resources/xwork-alias-conversion.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + #{ "aliasSource" : "aliasDest" } + + + + + + + + +