spring-projects / spring-projects/spring-batch

close() called twice for ItemReader and ItemWriter beans implementing ItemStream

Open
#3,801 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

has: minimal-example in: core in: infrastructure status: waiting-for-triage type: bug
Dominant language
Java
Stars
3k
Forks
2.5k
Avg merge
6d 53m
Merged PRs (30d)
3

Description

Bug description
If an ItemWriter or ItemReader bean is also implementing ItemStream, then its close() method will be invoked twice. First by TaskletStep.close() when the step is complete, then by Spring's DisposableBeanAdapter since close() is inferred as a destroy method.

Some beans cannot handle well the second invocation. For example, StaxEventItemWriter throws a NPE at the second close() call which results in a warning message:

2020-11-11 20:19:55.160  WARN 25948 --- [           main] o.s.b.f.support.DisposableBeanAdapter    : Destroy method 'close' on bean with name 'scopedTarget.writer' threw an exception: java.lang.NullPointerException: Cannot invoke "java.io.Writer.flush()" because "this.fWriter" is null

Environment
This is reproducible with Spring Batch 4.3.0 and Spring 5.2.10
Also reproducible with Spring Batch 3.0.10 and Spring 4.3.x

Expected behavior
I would expect that close() is invoked only at step completion by TaskletStep.close() since it's not intended to be a destroy method for the ItemStream implementors.
Also, ItemStream javadoc suggest that close() implementations should support multiple invocations without issues, but for StaxEventItemWriter this is not the case:

/**
* If any resources are needed for the stream to operate they need to be destroyed here. Once this method has been
* called all other methods (except open) may throw an exception.
*/
void close() throws ItemStreamException;

Workarounds exist, such as using @Bean(destroyMethod="") or not declaring the writer as a bean, but to me it looks like that the default behaviours of Spring Batch and Spring are in conflict here.

Minimal Complete Reproducible example
Check https://github.com/tiborsulyan/batch-test for a minimal working example. Juts launch the application and observe the warning message which is the result of the second close() invocation of the StaxEventItemWriter bean

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the warning with the linked minimal example, starting from JobConfiguration.java and the StaxEventItemWriter bean. Trace TaskletStep.close() alongside Spring's DisposableBeanAdapter destroy-method handling. Done means an ItemReader or ItemWriter implementing ItemStream is closed at step completion without a second invocation or warning.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, spring
Domain
backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.