Last active
October 17, 2021 12:42
-
-
Save fmbenhassine/163a4103d8850cf95b575020c167f1cc to your computer and use it in GitHub Desktop.
Spring Batch Bean Validation example #SpringBatch
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() ); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 + '\'' + | |
'}'; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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> |
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
@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
@netrapalsingh Looks like I missed the notification about your comment.. sorry for that.
Good question. There are two ways to do it depending on how you decide to deal with invalid items: either you filter them, or you throw an exception. This is configured with the
filter
flag:validatingItemProcessor.setFilter(true);
. So:ItemProcessListener#afterProcess
methodItemProcessListener#onError
methodHere is a quick example:
This example writes info to the standard output, but you can update it to write to a file. Of course, you need to register this listener in the step. Let me know if this helps.