In the previous post “Spring Batch Simple Example” we used “BeanWrapperFieldSetMapper” while reading the employee records from the file. The BeanWrapperFieldSetMapper created a new
instance of Employee class for every employee record in the file and set the instance fields.
We can more have control on the task performed by BeanWrapperFieldSetMapper by providing a custom implementation of FieldSetMapper interface.
This post explains the above point with an example
First we need to create a class which implements FieldSetMapper and provide implementation for the interface method “mapFieldSet” as shown below
Custom implementation of FieldSetMapper
package package2;
import org.springframework.batch.item.file.mapping.FieldSetMapper;
import org.springframework.batch.item.file.transform.FieldSet;
import org.springframework.validation.BindException;
public class EmployeeFieldSetMapper implements FieldSetMapper {
@Override
public Employee mapFieldSet(FieldSet fieldSet) throws BindException {
Employee employee = new Employee();
employee.setId(fieldSet.readString("id"));
employee.setName(fieldSet.readString("name"));
employee.setStatus(fieldSet.readString("status"));
employee.setSalary(fieldSet.readBigDecimal("salary"));
return employee;
}
}
In the above code, fieldSet parameter created by LineTokenizer implementation is passed to mapFieldSet method. In the method we create an uninitialized instance of employee class
and then set its fields by retrieving the values from fieldSet. The FieldSet class has read methods one for each java primitive type. We pass field name or field index as parameter
to FieldSet’s read method.
Below is xml configuration of reader bean
1 <bean id="reader" class="org.springframework.batch.item.file.FlatFileItemReader">
2 <property name="resource" value="file:FileInput.txt"/>
3 <property name="lineMapper">
4 <bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
5 <property name="lineTokenizer">
6 <bean class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
7 <property name="names" value="id,name,status,salary"/>
8 </bean>
9 </property>
10 <property name="fieldSetMapper">
11 <bean class="package2.EmployeeFieldSetMapper"/>
12 </property>
13 </bean>
14 </property>
15 </bean>
In the above xml configuration, from line 10 to 12, we set the fieldSetMapper property of DefaultLineMapper to our custom implementation of FieldSetMapper.
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="package2.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="package2.EmployeeFieldSetMapper"/>
</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.DelimitedLineAggregator">
<property name="fieldExtractor">
<bean class="org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor">
<property name="names" value="id,name,status,salary"/>
</bean>
</property>
</bean>
</property>
</bean>
<batch:job id="importEmployees">
<batch:step id="readWriteEmployees">
<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>
Thank you so much because with your EmployeeFieldSetMapper I have seen the light to a problem I had (I had… because I don’t have it anymore) for an object with 904 fields!!
Now the spent time in the reader is ridiculously low compared to before. Thank you!!