[ 
https://issues.apache.org/jira/browse/WW-5685?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Lukasz Lenart updated WW-5685:
------------------------------
    Description: 
h3. Problem

{{DefaultConversionFileProcessor.process}} iterates the entries of a 
{{-conversion.properties}} file and skips keys that are already present in the 
converter mapping. The skip is written as a {{break}} rather than a 
{{continue}}, so instead of skipping that one entry it abandons the whole file:

{code:java}
for (Map.Entry entry : prop.entrySet()) {
    String key = (String) entry.getKey();

    if (mapping.containsKey(key)) {
        break;          // <-- should be continue
    }
    ...
}
{code}

Every remaining entry in that properties file is silently dropped. There is no 
warning and no error; the affected properties simply fall back to default 
conversion at runtime.

h3. Why it triggers in practice

{{XWorkConverter.buildConverterMapping}} walks the class hierarchy — the class 
itself, then its interfaces, then its superclass — and passes _one shared, 
accumulating_ mapping into each {{addConverterMapping}} call. So a key claimed 
earlier in that walk aborts a later file entirely:
* A subclass {{Foo-conversion.properties}} declares {{bar}}.
* The superclass {{FooBase-conversion.properties}} declares {{bar}}, {{baz}} 
and {{qux}}.
* When the superclass file is processed, {{bar}} is already mapped, so {{baz}} 
and {{qux}} are never registered.

Annotation-derived entries land in the same map, so an {{@TypeConversion}} on 
the class can abort its properties file the same way.

h3. Nondeterminism

{{Properties}} extends {{Hashtable}} and {{entrySet()}} has no defined 
iteration order, so _which_ entries survive depends on hash order rather than 
file order. The same file can behave differently across JDK versions or after 
an unrelated key is added, which makes this hard to diagnose from the symptom.

h3. Related

WW-3871 fixed the identical {{break}} instead of {{continue}} defect in the 
annotation path ({{DefaultConversionAnnotationProcessor}}), merged as PR #1812 
and shipped in 7.3.0. This is the same bug in the properties-file path, which 
that change did not touch. It was noted during that work but deliberately left 
out of scope.

h3. Suggested fix

Change the {{break}} to {{continue}}, and add a regression test with a 
{{-conversion.properties}} file whose first key is already mapped, asserting 
the later keys still register. A hierarchy case (subclass and superclass files 
sharing a key) covers the realistic trigger.

  was:
h3. Problem

{{DefaultConversionFileProcessor.process}} iterates the entries of a 
{{-conversion.properties}} file and skips keys that are already present in the 
converter mapping. The skip is written as a {{break}} rather than a 
{{continue}}, so instead of skipping that one entry it abandons the whole file:

{code:java}
for (Map.Entry entry : prop.entrySet()) {
    String key = (String) entry.getKey();

    if (mapping.containsKey(key)) {
        break;          // <-- should be continue
    }
    ...
}
{code}

Every remaining entry in that properties file is silently dropped. There is no 
warning and no error; the affected properties simply fall back to default 
conversion at runtime.

h3. Why it triggers in practice

{{XWorkConverter.buildConverterMapping}} walks the class hierarchy — the class 
itself, then its interfaces, then its superclass — and passes _one shared, 
accumulating_ mapping into each {{addConverterMapping}} call. So a key claimed 
earlier in that walk aborts a later file entirely:
* A subclass {{Foo-conversion.properties}} declares {{bar}}.
* The superclass {{FooBase-conversion.properties}} declares {{bar}}, {{baz}} 
and {{qux}}.
* When the superclass file is processed, {{bar}} is already mapped, so {{baz}} 
and {{qux}} are never registered.

Annotation-derived entries land in the same map, so an {{@TypeConversion}} on 
the class can abort its properties file the same way.

h3. Nondeterminism

{{Properties}} extends {{Hashtable}} and {{entrySet()}} has no defined 
iteration order, so _which_ entries survive depends on hash order rather than 
file order. The same file can behave differently across JDK versions or after 
an unrelated key is added, which makes this hard to diagnose from the symptom.

h3. Related

WW-3871 fixed the identical {{break}}-instead-of-{{continue}} defect in the 
annotation path ({{DefaultConversionAnnotationProcessor}}), merged as PR #1812 
and shipped in 7.3.0. This is the same bug in the properties-file path, which 
that change did not touch. It was noted during that work but deliberately left 
out of scope.

h3. Suggested fix

Change the {{break}} to {{continue}}, and add a regression test with a 
{{-conversion.properties}} file whose first key is already mapped, asserting 
the later keys still register. A hierarchy case (subclass and superclass files 
sharing a key) covers the realistic trigger.


> DefaultConversionFileProcessor silently drops the rest of a 
> -conversion.properties file after the first already-mapped key
> --------------------------------------------------------------------------------------------------------------------------
>
>                 Key: WW-5685
>                 URL: https://issues.apache.org/jira/browse/WW-5685
>             Project: Struts 2
>          Issue Type: Bug
>          Components: Core Actions
>            Reporter: Lukasz Lenart
>            Priority: Major
>             Fix For: 7.4.0
>
>
> h3. Problem
> {{DefaultConversionFileProcessor.process}} iterates the entries of a 
> {{-conversion.properties}} file and skips keys that are already present in 
> the converter mapping. The skip is written as a {{break}} rather than a 
> {{continue}}, so instead of skipping that one entry it abandons the whole 
> file:
> {code:java}
> for (Map.Entry entry : prop.entrySet()) {
>     String key = (String) entry.getKey();
>     if (mapping.containsKey(key)) {
>         break;          // <-- should be continue
>     }
>     ...
> }
> {code}
> Every remaining entry in that properties file is silently dropped. There is 
> no warning and no error; the affected properties simply fall back to default 
> conversion at runtime.
> h3. Why it triggers in practice
> {{XWorkConverter.buildConverterMapping}} walks the class hierarchy — the 
> class itself, then its interfaces, then its superclass — and passes _one 
> shared, accumulating_ mapping into each {{addConverterMapping}} call. So a 
> key claimed earlier in that walk aborts a later file entirely:
> * A subclass {{Foo-conversion.properties}} declares {{bar}}.
> * The superclass {{FooBase-conversion.properties}} declares {{bar}}, {{baz}} 
> and {{qux}}.
> * When the superclass file is processed, {{bar}} is already mapped, so 
> {{baz}} and {{qux}} are never registered.
> Annotation-derived entries land in the same map, so an {{@TypeConversion}} on 
> the class can abort its properties file the same way.
> h3. Nondeterminism
> {{Properties}} extends {{Hashtable}} and {{entrySet()}} has no defined 
> iteration order, so _which_ entries survive depends on hash order rather than 
> file order. The same file can behave differently across JDK versions or after 
> an unrelated key is added, which makes this hard to diagnose from the symptom.
> h3. Related
> WW-3871 fixed the identical {{break}} instead of {{continue}} defect in the 
> annotation path ({{DefaultConversionAnnotationProcessor}}), merged as PR 
> #1812 and shipped in 7.3.0. This is the same bug in the properties-file path, 
> which that change did not touch. It was noted during that work but 
> deliberately left out of scope.
> h3. Suggested fix
> Change the {{break}} to {{continue}}, and add a regression test with a 
> {{-conversion.properties}} file whose first key is already mapped, asserting 
> the later keys still register. A hierarchy case (subclass and superclass 
> files sharing a key) covers the realistic trigger.



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

Reply via email to