0

I configured a StaxEventItemWriter like this:

@Bean
public StaxEventItemWriter<Foo> fooWriter() {
    return new StaxEventItemWriterBuilder<Foo>()
        .name("fooWriter")
        .marshaller(marshaller())
        .rootTagName("foos")
        .build();
}

And a MultiResourceItemWriter like this:

@Bean
public MultiResourceItemWriter<Foo> multiFooWriter() {
    return new MultiResourceItemWriterBuilder<Foo>()
        .name("multiFooWriter")
        .delegate(fooWriter())
        .itemCountLimitPerResource(100)
        .resourceSuffixCreator(index -> "-" + index + ".xml")
        .resource(new FileSystemResource("foo"))
        .build();
}

However, when I run a batch using these writers, I get the following exception:

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

I noticed it seems to have something to do with the transactional flushing, so I tried disabling transactions on the StaxEventItemWriter and then it indeed works:

@Bean
public StaxEventItemWriter<Foo> fooWriter() {
    return new StaxEventItemWriterBuilder<Foo>()
        .name("fooWriter")
        .marshaller(marshaller())
        .rootTagName("foos")
        .transactional(false) // Adding this works
        .build();
}

In addition, if I write to a single large XML file (eg. by using fooWriter() directly in my Step configuration in stead of multiFooWriter()), then the job also succeeds.

Is there a reason why StaxEventItemWriter combined with MultiResourceItemWriter does not work with transactions?

For completeness of the example, this is the Foo class I used and the ItemReader (but that's irrelevant to the question as the problem occurs with any reader/JAXB class):

@Getter
@XmlRootElement(name = "foo")
@XmlType(propOrder = { "itemCount" })
@NoArgsConstructor
public class Foo implements ItemCountAware {
    private int itemCount;

    @Override
    @XmlElement(name = "count")
    public void setItemCount(int count) {
        this.itemCount = count;
    }
}

For the reader I'm using AbstractItemCountingItemStreamItemReader in combination with ItemCountAware to generate some unique Foo POJO's (but it's irrelevant to the problem):

@Component
public class FooReader extends AbstractItemCountingItemStreamItemReader<Foo> {
    public FooReader() {
        setName("fooReader");
        setMaxItemCount(10000);
    }

    @Override
    protected Foo doRead() {
        return new Foo();
    }

    @Override
    protected void doOpen() {

    }

    @Override
    protected void doClose() {

    }
}
6
  • Try returning MultiResourceItemWriter instead of ItemWriter as that will also expose additional callbacks methods. Try to be as specific as you can when returning from @Bean methods. Commented Nov 20, 2025 at 12:51
  • That didn't have any effect sadly. I updated my question to include the more specific class names. Commented Nov 20, 2025 at 13:40
  • Well then I suspect it isn't compatible. Which sort of makes sense. As the buffer assumes that a file-channel is open, but midway of writing it could be suddenly swapped to a new resource due to the limit being reached (new file, new file channel) so the original one has closed. Commented Nov 20, 2025 at 15:24
  • I assume that as well, though I can't find any reference within the documentation that it wouldn't be supported (maybe I'm looking wrong though). Commented Nov 21, 2025 at 7:20
  • The fact that it isn't documented doesn't mean it doesn't apply! So I would suggest opening a ticket to add this to the documentation, probably of the TransactionAwareBufferedWriter and/or the MultiResourceItemWriter as that manages the writing and opening of files itself. Commented Nov 21, 2025 at 8:06

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.