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