Skip to content

ClosedChannelException when using StaxEventItemWriter in combination with MultiResourceItemWriter #5098

@g00glen00b

Description

@g00glen00b

Bug description
When using a StaxEventItemWriter in combination with a MultiResourceItemWriter, a ClosedChannelException is thrown with following stacktrace:

Caused by: java.nio.channels.ClosedChannelException: null
    at java.base/sun.nio.ch.FileChannelImpl.ensureOpen(FileChannelImpl.java:160) ~[na:na]
    at java.base/sun.nio.ch.FileChannelImpl.write(FileChannelImpl.java:284) ~[na:na]
    at org.springframework.batch.support.transaction.TransactionAwareBufferedWriter$1.complete(TransactionAwareBufferedWriter.java:121) ~[spring-batch-infrastructure-5.2.4.jar:5.2.4]
    at org.springframework.batch.support.transaction.TransactionAwareBufferedWriter$1.beforeCommit(TransactionAwareBufferedWriter.java:106) ~[spring-batch-infrastructure-5.2.4.jar:5.2.4]
    ... 44 common frames omitted

This only occurs as long as StaxEventItemWriter is configured to be transactional. After debugging some more it seemd to be related to the endDocument() method running after the writer has been closed, but I'm not sure if this is really the case.

Environment
Reproducible in multiple versions of Spring Batch (including 5.2.3, 6.0.0) on Java 21

Steps to reproduce

  1. Define a StaxEventItemWriter:

    @Bean
    public StaxEventItemWriter<Foo> fooWriter() {
        return new StaxEventItemWriterBuilder<Foo>()
            .name("fooWriter")
            .marshaller(marshaller())
            .rootTagName("foos")
            // Note, in Spring Batch 6.0, it seems to be required to pass a `resource` within the builder
            // even though it isn't used  due to being overriden by the `MultiResourceItemWriter`
            .resource(new FileSystemResource("foo/foo.xml"))
            .build();
    }
  2. Define a MultiResourceItemWriter:

    @Bean
    public MultiResourceItemWriter<Foo> multiFooWriter() {
        return new MultiResourceItemWriterBuilder<Foo>()
            .name("multiFooWriter")
            .delegate(fooWriter())
            .itemCountLimitPerResource(100)
            .resourceSuffixCreator(index -> "-" + index + ".xml")
            .resource(new FileSystemResource("foo"))
            .build();
    }
  3. Define a Job using this MultiResourceItemWriter and run it. It will result in the aforementioned stack trace. When I set .transactional(false) within the StaxEventItemWriter, the batch succeeds.

Expected behavior
I expect 100 XML files to be created (reader produces 10.000 items and writer creates a separate file per 100 items).

Minimal Complete Reproducible example
GitHub Repository

Additional notes
Relevant Stack Overflow thread I created: link
In this Stack Overflow thread it was discussed that this might be intentional behavior. If that's the case, I could send a PR to mention this in the documentation somewhere.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions