[ 
https://issues.apache.org/jira/browse/WW-3871?focusedWorklogId=1032237&page=com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel#worklog-1032237
 ]

ASF GitHub Bot logged work on WW-3871:
--------------------------------------

                Author: ASF GitHub Bot
            Created on: 25/Jul/26 19:12
            Start Date: 25/Jul/26 19:12
    Worklog Time Spent: 10m 
      Work Description: lukaszlenart commented on code in PR #1812:
URL: https://github.com/apache/struts/pull/1812#discussion_r3650845617


##########
core/src/main/java/org/apache/struts2/conversion/impl/XWorkConverter.java:
##########
@@ -498,51 +537,103 @@ protected void addConverterMapping(Map<String, Object> 
mapping, Class clazz) {
         String converterFilename = buildConverterFilename(clazz);
         fileProcessor.process(mapping, clazz, converterFilename);
 
-        // Process annotations
-        Annotation[] annotations = clazz.getAnnotations();
+        processClassLevelAnnotations(mapping, clazz);
+        processMethodAnnotations(mapping, clazz);
+        processFieldAnnotations(mapping, clazz);
+    }
 
-        for (Annotation annotation : annotations) {
-            if (annotation instanceof Conversion conversion) {
-                for (TypeConversion tc : conversion.conversions()) {
-                    if (mapping.containsKey(tc.key())) {
-                        break;
-                    }
-                    if (LOG.isDebugEnabled()) {
-                        if (StringUtils.isEmpty(tc.key())) {
-                            LOG.debug("WARNING! key of @TypeConversion [{}/{}] 
applied to [{}] is empty!", tc.converter(), tc.converterClass(), 
clazz.getName());
-                        } else {
-                            LOG.debug("TypeConversion [{}/{}] with key: [{}]", 
tc.converter(), tc.converterClass(), tc.key());
-                        }
-                    }
-                    annotationProcessor.process(mapping, tc, tc.key());
+    /**
+     * Registers the {@link TypeConversion} entries declared by a class level 
{@link Conversion}
+     * annotation.
+     */
+    private void processClassLevelAnnotations(Map<String, Object> mapping, 
Class clazz) {
+        for (Annotation annotation : clazz.getAnnotations()) {
+            if (!(annotation instanceof Conversion conversion)) {
+                continue;
+            }
+            for (TypeConversion tc : conversion.conversions()) {
+                String key = resolveKey(tc.type(), tc.rule(), tc.key());
+                if (key == null) {
+                    LOG.warn("Ignoring @TypeConversion [{}/{}] declared on 
[{}]: no key was given and a class level annotation has no property name to 
derive one from",
+                            tc.converter(), tc.converterClass(), 
clazz.getName());
+                    continue;
+                }
+                if (mapping.containsKey(key)) {
+                    continue;
                 }
+                LOG.debug("TypeConversion [{}/{}] declared on [{}] resolved to 
key [{}]",
+                        tc.converter(), tc.converterClass(), clazz.getName(), 
key);
+                annotationProcessor.process(mapping, tc, key);
             }
         }
+    }
 
-        // Process annotated methods
+    /**
+     * Registers {@link TypeConversion} annotations found on the class' 
methods.
+     */
+    private void processMethodAnnotations(Map<String, Object> mapping, Class 
clazz) {
         for (Method method : clazz.getMethods()) {
-            annotations = method.getAnnotations();
-            for (Annotation annotation : annotations) {
-                if (annotation instanceof TypeConversion tc) {
-                    String key = tc.key();
-                    // Default to the property name with prefix
-                    if (StringUtils.isEmpty(key)) {
-                        key = AnnotationUtils.resolvePropertyName(method);
-                        key = switch (tc.rule()) {
-                            case COLLECTION -> 
DefaultObjectTypeDeterminer.DEPRECATED_ELEMENT_PREFIX + key;
-                            case CREATE_IF_NULL -> 
DefaultObjectTypeDeterminer.CREATE_IF_NULL_PREFIX + key;
-                            case ELEMENT -> 
DefaultObjectTypeDeterminer.ELEMENT_PREFIX + key;
-                            case KEY -> DefaultObjectTypeDeterminer.KEY_PREFIX 
+ key;
-                            case KEY_PROPERTY -> 
DefaultObjectTypeDeterminer.KEY_PROPERTY_PREFIX + key;
-                            default -> key;
-                        };
-                        LOG.debug("Retrieved key [{}] from method name [{}]", 
key, method.getName());
-                    }
-                    if (mapping.containsKey(key)) {
-                        break;
-                    }
-                    annotationProcessor.process(mapping, tc, key);
+            for (Annotation annotation : method.getAnnotations()) {
+                if (!(annotation instanceof TypeConversion tc)) {
+                    continue;
+                }
+                String name = StringUtils.isEmpty(tc.key()) ? 
AnnotationUtils.resolvePropertyName(method) : tc.key();
+                String key = resolveKey(tc.type(), tc.rule(), name);
+                if (key == null) {

Review Comment:
   Correct, and fixed in c3f9b0771 — the method pass now skips an 
APPLICATION-scoped `@TypeConversion` with no explicit key and logs a WARN 
naming the declaring class and method.
   
   Worth recording that this path is not new: on `main` the method pass also 
fell through to the unprefixed property name for `APPLICATION`, so the 
unreachable entry predates this branch. Folding the fix in anyway, since this 
PR is what made the key-resolution rules explicit and the spec already states 
that APPLICATION keys are class names.
   
   Verified the mechanism before changing anything: `lookup(String, boolean)` 
is only ever reached with `clazz.getName()` (`XWorkConverter:315,318` → 
`:404-405`), so a `convertInt`-style key in the default map is indeed 
unreadable.





Issue Time Tracking
-------------------

    Worklog Id:     (was: 1032237)
    Time Spent: 40m  (was: 0.5h)

> TypeConversion annotation support improvement
> ---------------------------------------------
>
>                 Key: WW-3871
>                 URL: https://issues.apache.org/jira/browse/WW-3871
>             Project: Struts 2
>          Issue Type: Improvement
>          Components: Plugin - Convention
>    Affects Versions: 2.3.4.1
>            Reporter: Pavan Ananth
>            Assignee: Lukasz Lenart
>            Priority: Major
>             Fix For: 7.3.0
>
>          Time Spent: 40m
>  Remaining Estimate: 0h
>
> The annotation support for TypeConversion in Struts 2 is too literal an 
> interpretation of the XML support. For instance, I am required to supply this 
> if I have choose the CreateIfNull feature at a property level :
> @TypeConversion(key="CreateIfNull_users", rule=ConversionRule.CreateIfNull, 
> value="true")
> List<User> users;
> Given that the rule is CreateIfNull, the key can be constructed implicitly 
> using property name - why is it asked of an user to type in the full key. 
> This holds good for the other supported ConversionRules as well



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to