Skip to content

[Bug] ClassUtils removes the wrong indexFieldMap entry when excluding a column #976

Description

@Aias00

Search before asking

  • I searched in the issues and found nothing similar.

Fesod version

current main (50a6b5b)

JDK version

Temurin 25 (code path is version-independent, affects 8+)

Operating system

Linux (not OS-specific)

Steps To Reproduce

When a WriteHolder excludes a column and the bean has fields with explicit @ExcelProperty(index = N), the wrong entry is removed from the internal indexFieldMap, dropping an unrelated explicit-index field.

private static class ComplexEntity {
    @ExcelProperty(index = 0)
    private String id;        // explicit index 0 -> indexFieldMap[0]

    @ExcelProperty(index = 2)
    private String name;      // explicit index 2 -> indexFieldMap[2]

    @ExcelProperty(order = 10)
    private String email;     // no explicit index -> NOT in indexFieldMap

    private String noAnnotationField;
}

// exclude "email" (a field WITHOUT an explicit index)
WriteHolder writeHolder = ...; // excludeColumnFieldNames = {"email"}

FieldCache fieldCache = ClassUtils.declaredFields(ComplexEntity.class, writeHolder);
Map<Integer, FieldWrapper> indexFieldMap = fieldCache.getIndexFieldMap();

// expected: id and name remain (email was never in the map)
// actual: id (index 0) is gone; indexFieldMap == {2: name}

Current Behavior

After excluding email, indexFieldMap is {2: name} — the id entry (explicit index 0) has been wrongly removed, even though id was not excluded.

Expected Behavior

indexFieldMap should be {0: id, 2: name}. Excluding a field that has no explicit index must not perturb the explicit-index map.

Anything else?

Root cause: in the exclude/include loop, the ignored branch removes from indexFieldMap using the running counter index instead of the field's own key:

https://github.com/apache/fesod/blob/main/fesod-sheet/src/main/java/org/apache/fesod/sheet/util/ClassUtils.java#L364-L368

if (writeHolder.ignore(field.getFieldName(), entry.getKey())) {
    ignoreSet.add(field.getFieldName());
    indexFieldMap.remove(index);   // BUG: 'index' is the running counter, not the field's key
} else {
    ...
}

indexFieldMap is keyed by the field's explicit @ExcelProperty(index = N) value (see declaredOneField), and for explicit-index fields the sortedFieldMap position entry.getKey() equals that explicit index (see buildSortedAllFieldMap). So the ignored field's own entry is keyed by entry.getKey(), not by the running counter. Removing by the counter drops whichever explicit-index entry happens to match the counter and leaves the ignored field's entry in place when their indices differ.

The fix is to remove by the field's own key:

indexFieldMap.remove(key);

For a field with an explicit index, key == entry.getKey() is its indexFieldMap key, so its own entry is removed; for a field without an explicit index, key is not in indexFieldMap, so the call is a no-op (correct — it was never there).

The corruption is observable downstream: ExcelHeadProperty.initColumnProperties passes indexFieldMap.containsKey(entry.getKey()) as forceIndex into each Head, so an excluded unrelated field flips a sibling column's forceIndex from true to false, which DefaultAnalysisEventProcessor reads to drive head-to-column matching.

Are you willing to submit a PR?

  • I'm willing to submit a PR!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions