Skip to content

Instantly share code, notes, and snippets.

@fmbenhassine
Last active October 17, 2021 12:42
Show Gist options
  • Save fmbenhassine/163a4103d8850cf95b575020c167f1cc to your computer and use it in GitHub Desktop.
Save fmbenhassine/163a4103d8850cf95b575020c167f1cc to your computer and use it in GitHub Desktop.
Spring Batch Bean Validation example #SpringBatch
package com.example.demovalidation;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoValidationApplication {
public static void main(String[] args) {
SpringApplication.run(DemoValidationApplication.class, args);
}
}
package com.example.demovalidation;
import java.util.Arrays;
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.item.ItemProcessor;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.support.ListItemReader;
import org.springframework.batch.item.validator.SpringValidator;
import org.springframework.batch.item.validator.ValidatingItemProcessor;
import org.springframework.batch.item.validator.Validator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableBatchProcessing
public class JobConfiguration {
@Autowired
private JobBuilderFactory jobs;
@Autowired
private StepBuilderFactory steps;
@Bean
public ItemReader<Person> itemReader() {
Person person1 = new Person(1, "foo");
Person person2 = new Person(2, "");
return new ListItemReader<>(Arrays.asList(person1, person2));
}
@Bean
public ItemWriter<Person> itemWriter() {
return list -> {
for (Person person : list) {
System.out.println("person = " + person);
}
};
}
@Bean
public org.springframework.validation.Validator validator() {
// see https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#validation-beanvalidation-spring
return new org.springframework.validation.beanvalidation.LocalValidatorFactoryBean();
}
@Bean
public Validator<Person> springValidator() {
SpringValidator<Person> springValidator = new SpringValidator<>();
springValidator.setValidator(validator());
return springValidator;
}
@Bean
public ItemProcessor<Person, Person> itemProcessor() {
ValidatingItemProcessor<Person> validatingItemProcessor = new ValidatingItemProcessor<>(springValidator());
validatingItemProcessor.setFilter(true);
return validatingItemProcessor;
}
@Bean
public Step step1() {
return steps.get("step1")
.<Person, Person>chunk(1)
.reader(itemReader())
.processor(itemProcessor())
.writer(itemWriter())
.build();
}
@Bean
public Job job() {
return jobs.get("job")
.start(step1())
.build();
}
// can use a listener to log invalid items to file, db, etc
// use #afterProcess or #onProcessError depending on validatingItemProcessor.setFilter to true or false
static class InvalidItemsListener implements ItemProcessListener<Person, Person> {
@Override
public void beforeProcess(Person person) {
}
@Override
public void afterProcess(Person person, Person result) {
if (result == null) {
System.out.println(person + " has been filtered because it is invalid");
}
}
@Override
public void onProcessError(Person person, Exception e) {
System.out.println(person + " is invalid due to " + e.getMessage() );
}
}
}
package com.example.demovalidation;
import javax.validation.constraints.NotEmpty;
public class Person {
private int id;
@NotEmpty
private String name;
public Person() {
}
public Person(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>demo-validation</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>demo-validation</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
@agru-capco
Copy link

Hi Benas,

I am reading the records from a csv file, I need to do validate the recodes and write errors to a file with line numbers, how can I get access to line number?

Thanks,
Agru

@fmbenhassine
Copy link
Author

@agru-capco There is an interface called ItemCountAware that sets the number on each item. It could work in your case since the item number would be the same as the line number. What you need to do is make Person implement ItemCountAware and log the line number in the file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment