Search code examples
springspring-batch

org.springframework.batch.item.WriterNotOpenException: Writer must be open before it can be written to - in Spring batch Multithreading?


I've used FlatFileItemReader with the Classifier and ClassifierCompositeItemWriter in my project where we read Tab delimited file and convert it into CSV as a output file by performing some validation, enrichment etc process and create four output file which the logic written onto the Classifier implementation. So I am reading FlatFile and also creating another FlatFile.

Below us the snippet code

<bean id="classifier" class="com.XXXXXXXXX.SomeClassifier">
    <constructor-arg index="0" ref="oneMultiResource"/>
    <constructor-arg index="1" ref="twoMultiResource"/>
    <constructor-arg index="2" ref="threeMultiResource"/>
    <constructor-arg index="3" ref="fourMultiResource"/>
</bean>

<bean id="classifierCompositeItemWriter" class="org.springframework.batch.item.support.ClassifierCompositeItemWriter">
    <property name="classifier" ref="classifier"/>
</bean>

<bean id="onetCvsWriter" class="org.springframework.batch.item.file.FlatFileItemWriter" scope="step" >
    <property name="resource" value="file:${XXXXXXXXXXXXXXXXX}.#{jobParameters['year']}"/>
    <property name="shouldDeleteIfExists" value="true"/>
    <property name="shouldDeleteIfEmpty" value="true" />
    <property name="appendAllowed" value="true" />
    <property name="encoding" value="UTF-8"/>
    <property name="lineAggregator" ref="abLineAggregator"/>
    <property name="headerCallback" ref="headerCallback" />
</bean>

<bean id="oneMultiResource" class="org.springframework.batch.item.file.MultiResourceItemWriter" scope="step">
    <property name="name" value="MultiResourceWriter" />
    <property name="delegate" ref="onetCvsWriter" />
    <property name="resource" value="file:${XXXXXXXXXXXXXXXXX}.#{jobParameters['year']}" />
    <property name="itemCountLimitPerResource" value="500000"  />
    <property name="resourceSuffixCreator" ref="suffixCreator" />
</bean>

Error:

org.springframework.batch.item.WriterNotOpenException: Writer must be open before it can be written to
    at org.springframework.batch.item.file.FlatFileItemWriter.write(FlatFileItemWriter.java:236) ~[spring-batch-infrastructure-2.1.8.RELEASE.jar:?]
    at sun.reflect.GeneratedMethodAccessor16.invoke(Unknown Source) ~[?:?]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_202]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_202]
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.21.jar:5.3.21]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) ~[spring-aop-5.3.21.jar:5.3.21]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.21.jar:5.3.21]
    at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:137) ~[spring-aop-5.3.21.jar:5.3.21]
    at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:124) ~[spring-aop-5.3.21.jar:5.3.21]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.21.jar:5.3.21]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) ~[spring-aop-5.3.21.jar:5.3.21]
    at com.sun.proxy.$Proxy56.write(Unknown Source) ~[?:?]
    at org.springframework.batch.item.file.MultiResourceItemWriter.write(MultiResourceItemWriter.java:82) ~[spring-batch-infrastructure-2.1.8.RELEASE.jar:?]
    at sun.reflect.GeneratedMethodAccessor16.invoke(Unknown Source) ~[?:?]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_202]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_202]
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.21.jar:5.3.21]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) ~[spring-aop-5.3.21.jar:5.3.21]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.21.jar:5.3.21]
    at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:137) ~[spring-aop-5.3.21.jar:5.3.21]
    at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:124) ~[spring-aop-5.3.21.jar:5.3.21]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.21.jar:5.3.21]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) ~[spring-aop-5.3.21.jar:5.3.21]
    at com.sun.proxy.$Proxy54.write(Unknown Source) ~[?:?]

As per suggestion from here: FlatFileItemWriter - Writer must be open before it can be written to, how can we call in below in XML configurations?

itemWriter.open(new ExecutionContext());

Solution

  • The FlatFileItemWriter is not thread-safe as mentioned in its Javadocs, and therefore should not be used as such in a multi-threaded step. You can try to wrap it in a SynchronizedItemStreamWriter.