Chaining multiple JobParametersValidator implementations

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>
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s