Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Routing data to multiple files in item writer based on item's property as criteria

Tags:

spring-batch

I am getting a list of items in my reader.

There is a property called Code in each item object having several possible values not known to me before hand.

1) Based on the value of Codein each item, I want to write that particular item in a output file pertaining to that Code. For e.g. if my current item's Code is "abc", the item should be written in to abc.txt in the writer.

2) If there is a Code "xyz" in current item, for which the file is not present, a new file should get created and the item should go to that file.

3) For all such multiple files created based on Code, I also want to add a header and footer call back to enter some details e.g. count of items in each file.

Is it possible to have a writer, which satisfies above 3 requirements ?

I know that using multiresourceitemwriter, one can divide the data among multiple output files. But as far as I know, this division is based on the number of items. For e.g. first 10 items in file1, next 10 in file2 and so on.

But how to route data to output files based on an item property as mentioned in my question ?

I am well acquainted with Spring Batch and just need a little guidance since this is the first time I am facing this kind of issue.

Thanks for reading!

like image 424
Vicky Avatar asked Sep 17 '12 04:09

Vicky


People also ask

How ItemReader works in Spring Batch?

An Item Reader reads data into the spring batch application from a particular source, whereas an Item Writer writes data from Spring Batch application to a particular destination. An Item processor is a class which contains the processing code which processes the data read in to the spring batch.

What is ItemWriter in Java?

ItemWriter defines the batch artifact that writes to a list of items for chunk processing.

Which is the correct implementation of ItemWriter interface?

file. FlatFileItemWriter is the ItemWriter implementation provided to generate text file output. Similar to FlatFileItemReader in many respects, this class addresses the issues with file-based output in Java with a clean, consistent interface for you to use.

Can we have multiple readers in Spring Batch?

The core processing in Spring Batch framework can be group into 3 sections in each step: Reader. Processor.


2 Answers

If I understand your problem correctly, you need a few items.

First, a classifier that implements the Classifier interface

public class ItemCodeClassifier {
    @Classifier
    public String classify(Item item) {
        return item.getCode().getKey();// returns "abc", "xyz"
    }
}

Second a router implementation that consumes the above method

<bean id="classifier"  class="org.springframework.batch.classify.BackToBackPatternClassifier">
    <property name="routerDelegate">
        <bean class="ItemCodeClassifier" />
    </property>
    <property name="matcherMap">
        <map>
        <entry key="abc" value-ref="abcItemWriter" />
        <entry key="xyz" value-ref="xyzItemWriter" />
        </map>
    </property>
</bean>

And last of all, a ClassifierCompositeItemWriter

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

Did not compile the above but hope that it helps.

like image 180
Serkan Arıkuşu Avatar answered Oct 12 '22 21:10

Serkan Arıkuşu


Below solution worked for me. Compiled the Code and it's working fine.

First, you will need a Classifier. Either implement the Classifier interface or annotate classify() method with @Classifier.

Here I have used annotation.

public class MyClassifier {
    @Classifier
    public String classify(Policy pol) {
        return pol.getPolCode;// returns "01", "02"
    }
}

Add a Classifier bean

<bean id="myClassifier"  class="org.springframework.batch.classify.BackToBackPatternClassifier">
    <property name="routerDelegate">
        <bean class="MyClassifier" />
    </property>
    <property name="matcherMap">
        <map>
        <entry key="01" value-ref="pol01ItemWriter" />
        <entry key="02" value-ref="pol02ItemWriter" />
        </map>
    </property>
</bean>

Add your writer bean as like below

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

The Above Code may throw WriterNotOpenException. For this you need to add batch:stream to the step.

<batch:step id="step1">
    <batch:tasklet>
        <batch:chunk reader="reader" processor="processor" writer="ItemWriter" commit-interval="3">
            <batch:streams>
                <batch:stream ref="pol01ItemWriter"/>
                <batch:stream ref="pol02ItemWriter"/>
            </batch:streams>
        </batch:chunk>
    </batch:tasklet>
</batch:step>
like image 38
Mukesh Sabde Avatar answered Oct 12 '22 23:10

Mukesh Sabde