Skip to content

[Bug] PageReadListener re-delivers previous sheet's leftover rows when reading multiple sheets #960

Description

@nkuprins

Search before asking

  • I searched in the issues and found nothing similar.

Fesod version

current main (4b426ba)

JDK version

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

Operating system

Linux (not OS-specific)

Steps To Reproduce

public class Demo {
    @ExcelProperty("name")
    private String name;
    // getter/setter/no-arg constructor

    static List<Demo> rows(int count, String prefix) {
        List<Demo> list = new ArrayList<>();
        for (int i = 0; i < count; i++) {
            Demo d = new Demo();
            d.setName(prefix + i);
            list.add(d);
        }
        return list;
    }
}

// Write a workbook with two sheets: 3 rows and 4 rows
try (ExcelWriter writer = FesodSheet.write(file, Demo.class).build()) {
    writer.write(Demo.rows(3, "First"), FesodSheet.writerSheet(0, "sheet0").build());
    writer.write(Demo.rows(4, "Second"), FesodSheet.writerSheet(1, "sheet1").build());
}

// Read all sheets with one PageReadListener, page size 5
List<Demo> delivered = new ArrayList<>();
FesodSheet.read(file, Demo.class, new PageReadListener<Demo>(delivered::addAll, 5))
        .doReadAll();

System.out.println(delivered.size()); // prints 10, expected 7

Current Behavior

The consumer receives the batches [3 rows], [5 rows], [2 rows] - 10 rows in total. The delivered sequence is:

First0, First1, First2, First0, First1, First2, Second0, Second1, Second2, Second3

The 3 rows of sheet0 are delivered twice: once in the end-of-sheet flush, and again at the start of the first full batch produced while reading sheet1.

Expected Behavior

The consumer receives [3 rows] (end of sheet0) and [4 rows] (end of sheet1) - 7 rows, each row exactly once:

First0, First1, First2, Second0, Second1, Second2, Second3

Anything else?

Root cause: PageReadListener.doAfterAllAnalysed flushes cachedDataList to the consumer but never resets it, while invoke only replaces the list when a batch fills up. DefaultAnalysisEventProcessor.endSheet calls doAfterAllAnalysed after every sheet, and the same listener instance is shared by all sheets in doReadAll(), so the next sheet keeps appending to the already-delivered list and the leftover rows are emitted again.

The bug only triggers with the two-argument constructor (batchCount > 1) when a sheet's row count is not a multiple of the batch size; the no-arg default (BATCH_COUNT = 1) flushes every row, and single-sheet reads are unaffected. Upstream EasyExcel carries the same latent code.

The fix is a one-line reset of cachedDataList in doAfterAllAnalysed; I have the fix and a regression test ready and will open a PR referencing this issue.

Are you willing to submit a PR?

  • I'm willing to submit a PR!

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions