Use case – Consider we are reading thousands of records from the database and writing those in CSV files. We want to perform some validation for items before writing those to the CSV file.
Spring batch provides ValidatingItemProcessor class that can be used to perform validation on items.
The ValidatingItemProcessor class implements ItemProcess which is used to validate input and returns it without any modifications.
It contains the below methods.
public T process(T item)
public void setFilter(boolean filter)
public void afterPropertiesSet()
public void setValidator(Validator<? super T> validator)
Define Validator class i.e StudentValidator.java
In this example, we are going to perform very basic validation. If records from the database don’t contain an id or name throw a validation exception.
package com.springbatchexample.component;
import com.springbatchexample.entity.Student;
import org.springframework.batch.item.validator.ValidationException;
import org.springframework.batch.item.validator.Validator;
public class StudentValidator implements Validator<Student> {
@Override
public void validate(Student student) throws ValidationException {
if (student.getId() == null) {
throw new ValidationException("id must not be null");
}
if (student.getName() == null) {
throw new ValidationException("name must not be null");
}
}
}
Configure ValidatingItemProcessor class
@Bean
public ValidatingItemProcessor<Student> itemProcessor() {
ValidatingItemProcessor<Student> validatingItemProcessor = new ValidatingItemProcessor<>();
validatingItemProcessor.setValidator(new StudentValidator());
validatingItemProcessor.setFilter(true);
return validatingItemProcessor;
}
Call this ValidatingItemProcessor.
@Bean
public Step getDbToCsvStep() {
StepBuilder stepBuilder = stepBuilderFactory.get("getDbToCsvStep");
SimpleStepBuilder<Student, Student> simpleStepBuilder = stepBuilder.chunk(1);
return simpleStepBuilder.reader(reader()).processor(itemProcessor()).writer(writer()).build();
}
We need to call ValidatingItemProcessor using reader.processor()
method.
Let’s see the complete Spring Batch ValidatingItemProcessor Example using Spring boot
maven dependency
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.1.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
package structure
Model class
package com.springbatchexample.entity;
public class Student {
private Long id;
private String name;
private String rollNumber;
public Student() {
}
public Student(Long id, String name, String rollNumber) {
this.id = id;
this.name = name;
this.rollNumber = rollNumber;
}
//getter & setter
}
Define RowMapper
package com.springbatchexample.component;
import com.springbatchexample.entity.Student;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Component;
import java.sql.ResultSet;
import java.sql.SQLException;
@Component
public class StudentResultRowMapper implements RowMapper<Student> {
@Override
public Student mapRow(ResultSet rs, int i) throws SQLException {
Student student = new Student();
student.setId(rs.getLong("id"));
student.setRollNumber(rs.getString("roll_number"));
student.setName(rs.getString("name"));
return student;
}
}
This StudentResultRowMapper will get used while creating reader using JdbcCursorItemReader.
Define SpringBatchConfig file
package com.springbatchexample.config;
import com.springbatchexample.component.StudentResultRowMapper;
import com.springbatchexample.component.StudentValidator;
import com.springbatchexample.entity.Student;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.job.builder.FlowJobBuilder;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.core.step.builder.SimpleStepBuilder;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.item.database.JdbcCursorItemReader;
import org.springframework.batch.item.file.FlatFileItemWriter;
import org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor;
import org.springframework.batch.item.file.transform.DelimitedLineAggregator;
import org.springframework.batch.item.validator.ValidatingItemProcessor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.FileSystemResource;
import javax.sql.DataSource;
@EnableBatchProcessing
@Configuration
public class SpringBatchConfig {
@Autowired
private DataSource dataSource;
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Bean
public JdbcCursorItemReader<Student> reader() {
JdbcCursorItemReader<Student> reader = new JdbcCursorItemReader<>();
reader.setDataSource(dataSource);
reader.setSql("select id, roll_number, name from student");
reader.setRowMapper(new StudentResultRowMapper());
return reader;
}
@Bean
public FlatFileItemWriter<Student> writer() {
FlatFileItemWriter<Student> writer = new FlatFileItemWriter<>();
writer.setResource(new FileSystemResource("C://data/batch/data.csv"));
writer.setLineAggregator(getDelimitedLineAggregator());
return writer;
}
private DelimitedLineAggregator<Student> getDelimitedLineAggregator() {
BeanWrapperFieldExtractor<Student> beanWrapperFieldExtractor = new BeanWrapperFieldExtractor<Student>();
beanWrapperFieldExtractor.setNames(new String[]{"id", "rollNumber", "name"});
DelimitedLineAggregator<Student> aggregator = new DelimitedLineAggregator<Student>();
aggregator.setDelimiter(",");
aggregator.setFieldExtractor(beanWrapperFieldExtractor);
return aggregator;
}
@Bean
public Step getDbToCsvStep() {
StepBuilder stepBuilder = stepBuilderFactory.get("getDbToCsvStep");
SimpleStepBuilder<Student, Student> simpleStepBuilder = stepBuilder.chunk(1);
return simpleStepBuilder.reader(reader()).processor(itemProcessor()).writer(writer()).build();
}
@Bean
public Job dbToCsvJob() {
JobBuilder jobBuilder = jobBuilderFactory.get("dbToCsvJob");
jobBuilder.incrementer(new RunIdIncrementer());
FlowJobBuilder flowJobBuilder = jobBuilder.flow(getDbToCsvStep()).end();
Job job = flowJobBuilder.build();
return job;
}
@Bean
public ValidatingItemProcessor<Student> itemProcessor() {
ValidatingItemProcessor<Student> validatingItemProcessor = new ValidatingItemProcessor<>();
validatingItemProcessor.setValidator(new StudentValidator());
validatingItemProcessor.setFilter(true);
return validatingItemProcessor;
}
}
Define SpringMain class
package com.springbatchexample.main;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan(basePackages = "com.springbatchexample.*")
public class SpringMain {
public static void main(String[] args) {
SpringApplication.run(SpringMain.class, args);
}
}
application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/springbootcrudexample
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.hibernate.ddl-auto=create
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
server.port = 9091
spring.batch.initialize-schema=always
Note – For more details about the ValidatingItemProcessor spring batch see docs.
Other Spring Batch Tutorials.
- Spring Batch FlatFileItemReader Example
- JpaPagingItemReader Example
- JdbcPagingItemReader spring batch example
- StaxEventItemReader Example
- JsonItemReader Spring Batch Example
- JdbcCursorItemReader Spring Batch Example
- CompositeItemProcessor Spring Batch Example
- Spring Batch ItemReader Example
- StoredProcedureItemReader example
- AsyncItemProcessor Spring Batch Example