In this post under Spring Batch, I will show how to create batch files with formatted output. The example I use will generate output file where the width of the each fields are fixed.
In all my previous posts under Spring Batch, the output of the examples generated will be as shown below
Current Output
EMP_ID0,EMP_NAME0,EMP_STATUS0,0
EMP_ID1,EMP_NAME1,EMP_STATUS1,1
EMP_ID2,EMP_NAME2,EMP_STATUS2,2
EMP_ID3,EMP_NAME3,EMP_STATUS3,3
EMP_ID4,EMP_NAME4,EMP_STATUS4,4
EMP_ID5,EMP_NAME5,EMP_STATUS5,5
EMP_ID6,EMP_NAME6,EMP_STATUS6,6
EMP_ID7,EMP_NAME7,EMP_STATUS7,7
EMP_ID8,EMP_NAME8,EMP_STATUS8,8
EMP_ID9,EMP_NAME9,EMP_STATUS9,9
EMP_ID10,EMP_NAME10,EMP_STATUS10,10
EMP_ID11,EMP_NAME11,EMP_STATUS11,11
EMP_ID12,EMP_NAME12,EMP_STATUS12,12
EMP_ID13,EMP_NAME13,EMP_STATUS13,13
EMP_ID14,EMP_NAME14,EMP_STATUS14,14
In the above output the width of each fields is not fixed. It seems like the output are left justified. We can set the width of each fields resulting in the output as shown below
Expected Output
EMP_ID0 ,EMP_NAME0 ,EMP_STATUS0 ,0
EMP_ID1 ,EMP_NAME1 ,EMP_STATUS1 ,1
EMP_ID2 ,EMP_NAME2 ,EMP_STATUS2 ,2
EMP_ID3 ,EMP_NAME3 ,EMP_STATUS3 ,3
EMP_ID4 ,EMP_NAME4 ,EMP_STATUS4 ,4
EMP_ID5 ,EMP_NAME5 ,EMP_STATUS5 ,5
EMP_ID6 ,EMP_NAME6 ,EMP_STATUS6 ,6
EMP_ID7 ,EMP_NAME7 ,EMP_STATUS7 ,7
EMP_ID8 ,EMP_NAME8 ,EMP_STATUS8 ,8
EMP_ID9 ,EMP_NAME9 ,EMP_STATUS9 ,9
EMP_ID10 ,EMP_NAME10 ,EMP_STATUS10 ,10
EMP_ID11 ,EMP_NAME11 ,EMP_STATUS11 ,11
EMP_ID12 ,EMP_NAME12 ,EMP_STATUS12 ,12
EMP_ID13 ,EMP_NAME13 ,EMP_STATUS13 ,13
EMP_ID14 ,EMP_NAME14 ,EMP_STATUS14 ,14
This can be achieved with the help of org.springframework.batch.item.file.transform.FormatterLineAggregator class. It has property named “format” which takes the output pattern as a String.
The syntax format property value must follow is as shown below
%[argument_index$][flags][width][.precision]conversion
where
–> argument_index is a optional decimal integer indicating the position of the argument in the argument list.
–> flags is optional set of characters that modify the output format. The set of valid flags depends on the conversion.
–> width is optional non negative decimal integer indicating the minimum number of characters to write.
–> precision is optional field is non negative decimal integer normally used for restrict the number of characters.
–> conversion is required character field indicating how to format the argument. The set of valid conversions for a given argument depends on the argument’s data type.
Please refer to Spring batch documentation to know more about pattern string.
Below is xml configuration using FormatterLineAggregator class
1 <bean id="writer" class="org.springframework.batch.item.file.FlatFileItemWriter">
2 <property name="resource" value="file:DemoData2.txt"/>
3 <property name="lineAggregator">
4 <bean class="org.springframework.batch.item.file.transform.FormatterLineAggregator">
5 <property name="fieldExtractor">
6 <bean class="org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor">
7 <property name="names" value="id,name,status,salary"/>
8 </bean>
9 </property>
10 <property name="format" value="%-10s,%-15s,%-15s,%-15s"/>
11 </bean>
12 </property>
13 </bean>
At line 10, I set the format property with the value “%-10s%-15s%-15s%-15s”, where
–> “-” is a flag indicating the output of each field should be left justified
–> 10 and 15 is width of the field
–> s means the result of arg.toString() method
–> , is the delimiter
Below is the complete xml configuration for your reference
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:batch="http://www.springframework.org/schema/batch"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch.xsd">
<bean id="employee" class="package6.Employee" scope="prototype"/>
<bean id="reader" class="org.springframework.batch.item.file.FlatFileItemReader">
<property name="resource" value="file:FileInput.txt"/>
<property name="lineMapper">
<bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
<property name="lineTokenizer">
<bean class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
<property name="names" value="id,name,status,salary"/>
</bean>
</property>
<property name="fieldSetMapper">
<bean class="org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper">
<property name="prototypeBeanName" value="employee"/>
</bean>
</property>
</bean>
</property>
</bean>
<bean id="writer" class="org.springframework.batch.item.file.FlatFileItemWriter">
<property name="resource" value="file:DemoData2.txt"/>
<property name="lineAggregator">
<bean class="org.springframework.batch.item.file.transform.FormatterLineAggregator">
<property name="fieldExtractor">
<bean class="org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor">
<property name="names" value="id,name,status,salary"/>
</bean>
</property>
<property name="format" value="%-10s,%-15s,%-15s,%-15s"/>
</bean>
</property>
</bean>
<batch:job id="importProductsJob">
<batch:step id="readWriteProducts">
<batch:tasklet>
<batch:chunk reader="reader" writer="writer" commit-interval="50"/>
</batch:tasklet>
</batch:step>
</batch:job>
<bean id="transactionManager" class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />
<bean id="jobRepository" class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean">
<property name="transactionManager" ref="transactionManager"/>
</bean>
<bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
<property name="jobRepository" ref="jobRepository"/>
</bean>
</beans>