This is an automated email from the ASF dual-hosted git repository. lukaszlenart pushed a commit to branch WW-5656-deprecate-collection-conversion-rule in repository https://gitbox.apache.org/repos/asf/struts.git
commit 9fb5434970d2473f692c3dce1013cf827cf325e0 Author: Lukasz Lenart <[email protected]> AuthorDate: Sat Aug 1 12:16:38 2026 +0200 WW-5656 docs(conversion): mark ConversionRule.COLLECTION and the Collection_ prefix as deprecated Both have been documented as deprecated since WebWork 2.1.x, but neither carried an actual @Deprecated annotation, so users only ever learned about it from prose or from an INFO log line that fires solely when the fallback is hit. Runtime behaviour is unchanged - the Collection_ fallback keeps working, and COLLECTION remains a legal @TypeConversion rule handled identically to ELEMENT. Call sites that reference either element deliberately carry a suppression and a note saying why. Also deprecates XWorkConverter.CONVERSION_COLLECTION_PREFIX, a second public spelling of the same Collection_ prefix that the framework itself never reads. Co-Authored-By: Claude Opus 5 <[email protected]> --- .../struts2/conversion/annotations/ConversionRule.java | 15 ++++++++++++++- .../struts2/conversion/annotations/TypeConversion.java | 5 +++-- .../impl/DefaultConversionAnnotationProcessor.java | 3 +++ .../conversion/impl/DefaultConversionFileProcessor.java | 3 +++ .../conversion/impl/DefaultObjectTypeDeterminer.java | 7 +++++++ .../apache/struts2/conversion/impl/XWorkConverter.java | 6 ++++++ .../apache/struts2/conversion/ConversionTestAction.java | 2 ++ .../conversion/annotations/ConversionRuleTest.java | 2 ++ .../struts2/conversion/impl/XWorkConverterTest.java | 1 + .../test/java/org/apache/struts2/test/AnnotationUser.java | 2 ++ 10 files changed, 43 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/org/apache/struts2/conversion/annotations/ConversionRule.java b/core/src/main/java/org/apache/struts2/conversion/annotations/ConversionRule.java index db9793ecd..4f8ab7723 100644 --- a/core/src/main/java/org/apache/struts2/conversion/annotations/ConversionRule.java +++ b/core/src/main/java/org/apache/struts2/conversion/annotations/ConversionRule.java @@ -28,7 +28,17 @@ import org.apache.struts2.conversion.impl.DefaultObjectTypeDeterminer; */ public enum ConversionRule { - PROPERTY, COLLECTION, MAP, KEY, KEY_PROPERTY, ELEMENT, CREATE_IF_NULL; + PROPERTY, + + /** + * @deprecated since 7.3.0, use {@link #ELEMENT} instead. The {@code Collection_xxx} key format has + * been superseded by {@code Element_xxx} since WebWork 2.1.x; both are handled identically by the + * engine, and {@code Element_xxx} additionally covers the values of a {@code Map}. + */ + @Deprecated(since = "7.3.0") + COLLECTION, + + MAP, KEY, KEY_PROPERTY, ELEMENT, CREATE_IF_NULL; /** * The prefix a conversion mapping key carries for this rule, as read back by @@ -43,6 +53,9 @@ public enum ConversionRule { * @return the mapping key prefix, never null; an empty string when the rule has none * @since 7.3.0 */ + // the switch is deliberately exhaustive with no default, so the deprecated COLLECTION arm - and + // with it the reference to the deprecated prefix constant - cannot be dropped + @SuppressWarnings("deprecation") public String prefix() { return switch (this) { case COLLECTION -> DefaultObjectTypeDeterminer.DEPRECATED_ELEMENT_PREFIX; diff --git a/core/src/main/java/org/apache/struts2/conversion/annotations/TypeConversion.java b/core/src/main/java/org/apache/struts2/conversion/annotations/TypeConversion.java index 062fc167d..ed38a9e80 100644 --- a/core/src/main/java/org/apache/struts2/conversion/annotations/TypeConversion.java +++ b/core/src/main/java/org/apache/struts2/conversion/annotations/TypeConversion.java @@ -141,7 +141,7 @@ import java.lang.annotation.Target; * @TypeConversion(rule = ConversionRule.CREATE_IF_NULL, value = "true") * private List users = null; * - * @TypeConversion(rule = ConversionRule.COLLECTION, converterClass = String.class) + * @TypeConversion(rule = ConversionRule.ELEMENT, converterClass = String.class) * public void setUsers( List users ) { * this.users = users; * } @@ -196,7 +196,8 @@ public @interface TypeConversion { ConversionType type() default ConversionType.CLASS; /** - * The ConversionRule can be a PROPERTY, KEY, KEY_PROPERTY, ELEMENT, COLLECTION (deprecated) or a MAP. + * The ConversionRule can be a PROPERTY, KEY, KEY_PROPERTY, ELEMENT, CREATE_IF_NULL or a MAP. + * {@link ConversionRule#COLLECTION} is also accepted, but deprecated - use ELEMENT instead. * Note: Collection and Map conversion rules can be determined via org.apache.struts2.conversion.impl.DefaultObjectTypeDeterminer. * * @see DefaultObjectTypeDeterminer diff --git a/core/src/main/java/org/apache/struts2/conversion/impl/DefaultConversionAnnotationProcessor.java b/core/src/main/java/org/apache/struts2/conversion/impl/DefaultConversionAnnotationProcessor.java index fcf2d727d..1c555d2f7 100644 --- a/core/src/main/java/org/apache/struts2/conversion/impl/DefaultConversionAnnotationProcessor.java +++ b/core/src/main/java/org/apache/struts2/conversion/impl/DefaultConversionAnnotationProcessor.java @@ -53,6 +53,9 @@ public class DefaultConversionAnnotationProcessor implements ConversionAnnotatio this.converterHolder = converterHolder; } + // ConversionRule.COLLECTION is referenced deliberately: it remains a legal value on @TypeConversion + // and has to keep being treated exactly like ELEMENT. + @SuppressWarnings("deprecation") public void process(Map<String, Object> mapping, TypeConversion tc, String key) { LOG.debug("TypeConversion [{}/{}] with key: [{}]", tc.converter(), tc.converterClass(), key); if (key == null) { diff --git a/core/src/main/java/org/apache/struts2/conversion/impl/DefaultConversionFileProcessor.java b/core/src/main/java/org/apache/struts2/conversion/impl/DefaultConversionFileProcessor.java index 24db040b4..194ebb28d 100644 --- a/core/src/main/java/org/apache/struts2/conversion/impl/DefaultConversionFileProcessor.java +++ b/core/src/main/java/org/apache/struts2/conversion/impl/DefaultConversionFileProcessor.java @@ -52,6 +52,9 @@ public class DefaultConversionFileProcessor implements ConversionFileProcessor { this.converterCreator = converterCreator; } + // DEPRECATED_ELEMENT_PREFIX is referenced deliberately: existing -conversion.properties files may + // still spell Collection_xxx, and those keys must keep being recognised as element metadata. + @SuppressWarnings("deprecation") public void process(Map<String, Object> mapping, Class clazz, String converterFilename) { try { InputStream is = fileManager.loadFile(ClassLoaderUtil.getResource(converterFilename, clazz)); diff --git a/core/src/main/java/org/apache/struts2/conversion/impl/DefaultObjectTypeDeterminer.java b/core/src/main/java/org/apache/struts2/conversion/impl/DefaultObjectTypeDeterminer.java index db56ae075..d4cfaa1dc 100644 --- a/core/src/main/java/org/apache/struts2/conversion/impl/DefaultObjectTypeDeterminer.java +++ b/core/src/main/java/org/apache/struts2/conversion/impl/DefaultObjectTypeDeterminer.java @@ -62,6 +62,13 @@ public class DefaultObjectTypeDeterminer implements ObjectTypeDeterminer { public static final String ELEMENT_PREFIX = "Element_"; public static final String KEY_PROPERTY_PREFIX = "KeyProperty_"; public static final String CREATE_IF_NULL_PREFIX = "CreateIfNull_"; + /** + * @deprecated since 7.3.0, use {@link #ELEMENT_PREFIX} instead. The {@code Collection_xxx} key + * format has been superseded by {@code Element_xxx} since WebWork 2.1.x. Existing + * {@code -conversion.properties} files keep working: {@link #getElementClass(Class, String, Object)} + * still falls back to this prefix. + */ + @Deprecated(since = "7.3.0") public static final String DEPRECATED_ELEMENT_PREFIX = "Collection_"; private final ReflectionProvider reflectionProvider; diff --git a/core/src/main/java/org/apache/struts2/conversion/impl/XWorkConverter.java b/core/src/main/java/org/apache/struts2/conversion/impl/XWorkConverter.java index 7780f3fda..2c578233c 100644 --- a/core/src/main/java/org/apache/struts2/conversion/impl/XWorkConverter.java +++ b/core/src/main/java/org/apache/struts2/conversion/impl/XWorkConverter.java @@ -152,6 +152,12 @@ public class XWorkConverter extends DefaultTypeConverter { public static final String REPORT_CONVERSION_ERRORS = "report.conversion.errors"; public static final String CONVERSION_PROPERTY_FULLNAME = "conversion.property.fullName"; public static final String CONVERSION_ERROR_PROPERTY_PREFIX = "invalid.fieldvalue."; + /** + * @deprecated since 7.3.0, use {@link DefaultObjectTypeDeterminer#ELEMENT_PREFIX} instead. A second + * public spelling of the same deprecated {@code Collection_} prefix as + * {@link DefaultObjectTypeDeterminer#DEPRECATED_ELEMENT_PREFIX}, unused by the framework itself. + */ + @Deprecated(since = "7.3.0") public static final String CONVERSION_COLLECTION_PREFIX = "Collection_"; public static final String LAST_BEAN_CLASS_ACCESSED = "last.bean.accessed"; diff --git a/core/src/test/java/org/apache/struts2/conversion/ConversionTestAction.java b/core/src/test/java/org/apache/struts2/conversion/ConversionTestAction.java index a54417d23..d172daea0 100644 --- a/core/src/test/java/org/apache/struts2/conversion/ConversionTestAction.java +++ b/core/src/test/java/org/apache/struts2/conversion/ConversionTestAction.java @@ -71,6 +71,8 @@ public class ConversionTestAction implements Action { return users; } + // deliberately declares the deprecated COLLECTION rule, to keep the Collection_ fallback covered + @SuppressWarnings("deprecation") @TypeConversion(rule = ConversionRule.COLLECTION, converterClass = String.class) public void setUsers( List users ) { this.users = users; diff --git a/core/src/test/java/org/apache/struts2/conversion/annotations/ConversionRuleTest.java b/core/src/test/java/org/apache/struts2/conversion/annotations/ConversionRuleTest.java index 04e63e1ec..819e82094 100644 --- a/core/src/test/java/org/apache/struts2/conversion/annotations/ConversionRuleTest.java +++ b/core/src/test/java/org/apache/struts2/conversion/annotations/ConversionRuleTest.java @@ -24,6 +24,8 @@ import static org.junit.Assert.assertEquals; public class ConversionRuleTest { + // COLLECTION is deprecated but must keep deriving Collection_ for existing annotations + @SuppressWarnings("deprecation") @Test public void prefixIsDefinedForEveryRule() { assertEquals("", ConversionRule.PROPERTY.prefix()); diff --git a/core/src/test/java/org/apache/struts2/conversion/impl/XWorkConverterTest.java b/core/src/test/java/org/apache/struts2/conversion/impl/XWorkConverterTest.java index 3f107c8a0..eec40bd9e 100644 --- a/core/src/test/java/org/apache/struts2/conversion/impl/XWorkConverterTest.java +++ b/core/src/test/java/org/apache/struts2/conversion/impl/XWorkConverterTest.java @@ -836,6 +836,7 @@ public class XWorkConverterTest extends XWorkTestCase { XWorkConverter.resolveKey(ConversionType.CLASS, ConversionRule.CREATE_IF_NULL, "users")); } + @SuppressWarnings("deprecation") public void testResolveKeyLeavesAnAlreadyPrefixedKeyAlone() { assertEquals("KeyProperty_annotatedBeanMap", XWorkConverter.resolveKey(ConversionType.CLASS, ConversionRule.KEY_PROPERTY, "KeyProperty_annotatedBeanMap")); diff --git a/core/src/test/java/org/apache/struts2/test/AnnotationUser.java b/core/src/test/java/org/apache/struts2/test/AnnotationUser.java index 22080b73b..a1ce4539c 100644 --- a/core/src/test/java/org/apache/struts2/test/AnnotationUser.java +++ b/core/src/test/java/org/apache/struts2/test/AnnotationUser.java @@ -83,6 +83,8 @@ public class AnnotationUser implements AnnotationUserMarker { list = l; } + // deliberately declares the deprecated COLLECTION rule, to keep the Collection_ fallback covered + @SuppressWarnings("deprecation") @KeyProperty(value = "name") @TypeConversion(converterClass = String.class, rule = ConversionRule.COLLECTION) public List getList() {
