0
votes

I am using spring batch in order to read data from the database (using partitioning) and writing the same to a set of files based upon entry keys - 1,2,3,4.

I have created a CompositeItemWriter which is a composition of two ClassifierCompositeItemWriter(s). Even though I have registered the individual writers as stream, I still get the following exception:

org.springframework.batch.item.WriterNotOpenException: Writer must be open before it can be written to

I even tried registering ItemWriter1 and ItemWriter2 as streams, but, that gives me a different error:

Caused by: java.lang.IllegalStateException: Cannot convert value of type [com.sun.proxy.$Proxy13 implementing org.springframework.batch.item.ItemWriter,java.io.Serializable,org.springframework.aop.scope.ScopedObject,org.springframework.aop.framework.AopInfrastructureBean,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised] to required type [org.springframework.batch.item.ItemStream] for property 'streams[0]': no matching editors or conversion strategy found
    at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:264)
    at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:128)
    at org.springframework.beans.TypeConverterDelegate.convertToTypedArray(TypeConverterDelegate.java:463)
    at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:195)
    at org.springframework.beans.BeanWrapperImpl.convertIfNecessary(BeanWrapperImpl.java:448)
    ... 74 more

I have even implemented the ItemStream in the writers, but, it does not work yet.

public class WriterA1 implements ItemWriter<List<Object>>, ItemStream {
...
}

The following is the xml configuration:

...

<job id="abcJob" xmlns="http://www.springframework.org/schema/batch"
    restartable="true"> 

    <step id="masterStep">
        <partition step="slaveStep" partitioner="abcPartitioner">
            <handler grid-size="${grid-size}" task-executor="abcTaskExecutor" />
        </partition>            
    </step> 

</job>

<step id="slaveStep" xmlns="http://www.springframework.org/schema/batch">
        <tasklet transaction-manager="transactionManager">
            <chunk reader="abcReader" writer="abcWriter"
                processor="abcProcessor" commit-interval="${a}" skip-limit="${b}" retry-limit="${c}" >

                <streams>
                    <!-- 
                    <stream ref="ItemWriter1"/> 
                    <stream ref="ItemWriter2"/>
                     -->                        
                    <stream ref="WriterA1"/>
                    <stream ref="WriterB2"/>
                    <stream ref="WriterC3"/>
                    <stream ref="WriterD4"/>                                            
                    <stream ref="WriterA5"/>
                    <stream ref="WriterB6"/>
                    <stream ref="WriterC7"/>
                    <stream ref="WriterD8"/> 

                </streams>                

            </chunk>
            <listeners>
                ...                                     
            </listeners>                                                
        </tasklet>              
    </step> 


<bean id="abcWriter" class="org.springframework.batch.item.support.CompositeItemWriter" scope="step">
    <property name="delegates">
        <list>              
            <ref bean="ItemWriter1" />
            <ref bean="ItemWriter2" /> 
        </list>
    </property>
</bean>  

<bean id="ItemWriter1" class="org.springframework.batch.item.support.ClassifierCompositeItemWriter" scope="step">
    <property name="classifier">
        <bean
            class="org.springframework.classify.BackToBackPatternClassifier">
            <property name="routerDelegate">
                <bean class="xxx.xxx.xxx.xxx.Classifier1" scope="step"/>
            </property>
            <property name="matcherMap">
                <map>
                     <entry key="1" value-ref="WriterA1" />
                     <entry key="2" value-ref="WriterB2" />
                     <entry key="3" value-ref="WriterC3" />
                     <entry key="4" value-ref="WriterD4" />
                </map>
            </property>
        </bean>     
    </property>
</bean>

<bean id="ItemWriter2" class="org.springframework.batch.item.support.ClassifierCompositeItemWriter" scope="step">
    <property name="classifier">
        <bean
            class="org.springframework.classify.BackToBackPatternClassifier">
            <property name="routerDelegate">
                <bean class="xxx.xxx.xxx.xxx.Classifier2" scope="step"/>
            </property>
            <property name="matcherMap">
                <map>
                     <entry key="1" value-ref="WriterA5" />
                     <entry key="2" value-ref="WriterB6" />
                     <entry key="3" value-ref="WriterC7" />
                     <entry key="4" value-ref="WriterD8" />
                </map>
            </property>
        </bean>     
    </property>
</bean>

 <bean id="WriterA1" class="xxx.xxx.xxx.xxx.WriterA1" scope="step">

 </bean>
 <bean id="WriterB2" class="xxx.xxx.xxx.xxx.WriterB2" scope="step">

 </bean>
<bean id="WriterC3" class="xxx.xxx.xxx.xxx.WriterC3" scope="step">

</bean>
<bean id="WriterD4" class="xxx.xxx.xxx.xxx.WriterD4" scope="step">

</bean>
  <bean id="WriterA5" class="xxx.xxx.xxx.xxx.WriterA5" scope="step">

  </bean>
  <bean id="WriterB6" class="xxx.xxx.xxx.xxx.WriterB6" scope="step">

  </bean>
 <bean id="WriterC7" class="xxx.xxx.xxx.xxx.WriterC7" scope="step">

 </bean>
 <bean id="WriterD8" class="xxx.xxx.xxx.xxx.WriterD8" scope="step">

 </bean>

Please advise.

1
Which class (or even better, which bean) is throwing org.springframework.batch.item.WriterNotOpenException?Artefacto
WriterA1 (<bean id="WriterA1" class="xxx.xxx.xxx.xxx.WriterA1" scope="step"> </bean>) is throwing an exception. My understanding is that any of the writers that are being invoked based upon the entry key is will throw the same exception.ridsoc
Further to my note above: The item writers uses BeanIOFlatFileItemWriter in the overridden "write" method. Initially, I had configured the writers to use BeanIOFlatFileItemWriter through xml configuration, but, it was unable to detect the drive where the file had to be created stating that "Access is denied" which should not have occurred as I have admin priviledges on the local machine. Hence, I had to resort to writing the individual item writers.ridsoc

1 Answers

0
votes

You have three types of writers. From top to bottom:

  • abcWriter is a CompositeItemWriter. It implements ItemStream by delegating the ItemStream method calls to the delegates (here ItemWriter1 and ItemWriter2), provided they implement ItemStream. Which is not the case. But even if they implemented ItemStream, you shouldn't separately register ItemWriter1 and ItemWriter2 as streams in the step configuration (there's another independent reason in the next bullet point).

  • ItemWriter1/ItemWriter2 are ClassifierCompositeItemWriters. This class doesn't implement ItemStream, so you must not register them as streams in the step configuration.

  • WriterA1 are of type BeanIOFlatFileItemWriter and therefore implement ItemStream. Because the ClassifierCompositeItemWriter that wraps them doesn't call their ItemStream methods (unlike CompositeItemWriter), you must register each one of them as streams in the step configuration.

But this is what you claim you have. Yet your scoped-scoped WriterXX beans are being proxied (with interface proxy mode) through singleton beans that don't implement ItemStream or ItemStreamWriter, instead only ItemWriter. Make sure that the classes you have inside the <bean> elements do implement ItemStream. You can also try creating the scoped proxy bean explicitly (using ScopedProxyFactoryBean and setting the interfaces property). Or you can try putting a breakpoint in ScopedProxyFactoryBean::setBeanFactory breaking when targetBeanName is contains the string WriterXX (it will be something like stepScopedTarget.WriterD8) and try to understand why the ItemStream interface is not being proxied.