In this post under Spring Batch, I will show how to chain multiple JobParametersValidator interface implementations.
For our example I will create two JobParametersValidator interface implementations as shown below
Validator1
package package23;
import java.util.Map;
import org.springframework.batch.core.JobParameter;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersInvalidException;
import org.springframework.batch.core.JobParametersValidator;
public class Validator1 implements JobParametersValidator {
@Override
public void validate(JobParameters jobParameters) throws JobParametersInvalidException {
Map map = jobParameters.getParameters();
System.out.println("Validator1 validation begins");
for(String key : map.keySet()) {
System.out.println(key + ":" + map.get(key));
}
System.out.println("Validator1 validation ends");
}
}
Validator2
package package23;
import java.util.Map;
import org.springframework.batch.core.JobParameter;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersInvalidException;
import org.springframework.batch.core.JobParametersValidator;
public class Validator2 implements JobParametersValidator {
@Override
public void validate(JobParameters jobParameters) throws JobParametersInvalidException {
Map map = jobParameters.getParameters();
System.out.println("Validator2 validation begins");
for(String key : map.keySet()) {
System.out.println(key + ":" + map.get(key));
}
System.out.println("Validator2 validation ends");
}
}
As you see from the above code, both implementations just print a statement in the console.
Next I will show how to chain these two implementations as shown below
1 <bean id="validator1" class="package23.Validator1"/>
2
3 <bean id="validator2" class="package23.Validator2"/>
4
5 <bean id="compositeValidator" class="org.springframework.batch.core.job.CompositeJobParametersValidator">
6 <property name="validators">
7 <list>
8 <ref bean="validator1" />
9 <ref bean="validator2" />
10 </list>
11 </property>
12 </bean>
13
14 <batch:job id="importProductsJob">
15 <batch:step id="readWriteProducts">
16 <batch:tasklet>
17 <batch:chunk reader="reader" writer="writer" commit-interval="50"/>
18 </batch:tasklet>
19 </batch:step>
20 <batch:validator ref="compositeValidator"/>
21 </batch:job>
As shown in the above xml, at line 1 and 3, I have created two bean definitions one for Validator1 class (id as “validator1”) and another for Validator2 class (id as “validator2”).
At line 5 I have created another bean with id “compositeValidator” of class CompositeJobParametersValidator. Then at line 6 we set it’s property “validators” with a list of validators that contains previously defined validator1 and validator2.
Each validator in the “validators” list is executed in the order they are added to the list.
At line 20, we set the “validator” property of Job bean with the bean of “compositeValidator” instead of individual validators.
So with the help of CompositeJobParametersValidator class we chain multiple JobParametersValidator implementations.
Below is the complete xml 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="package23.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:FileOutput.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>
<bean id="validator1" class="package23.Validator1"/>
<bean id="validator2" class="package23.Validator2"/>
<bean id="compositeValidator" class="org.springframework.batch.core.job.CompositeJobParametersValidator">
<property name="validators">
<list>
<ref bean="validator1" />
<ref bean="validator2" />
</list>
</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:validator ref="compositeValidator"/>
</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>