-
-
Save fmbenhassine/163a4103d8850cf95b575020c167f1cc to your computer and use it in GitHub Desktop.
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> |
@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:
- If you decide to filter them, you can use
ItemProcessListener#afterProcess
method - If you decide to throw an exception, you can use
ItemProcessListener#onError
method
Here is a quick example:
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 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.
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.
How can we log the validation failed records in log file, Thanks.