Skipping Faulty Records with SkipPolicy in Spring Batch

Robust Error Handling in Spring Batch Using SkipPolicy

In real-world batch processing, data inconsistencies and malformed records are common. Spring Batch provides a robust mechanism to handle such scenarios gracefully using SkipPolicy. This tutorial explains how to skip faulty records during processing and log them for later review.

๐Ÿ“Œ What is SkipPolicy?

SkipPolicy is a Spring Batch interface that determines whether a particular exception should cause the step to skip the current item and continue processing or fail the job. This allows you to define custom logic for what should be considered skippable.

๐Ÿ”ง Maven Dependencies

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-batch</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
  <groupId>com.h2database</groupId>
  <artifactId>h2</artifactId>
  <scope>runtime</scope>
</dependency>

⚙️ application.properties

spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.h2.console.enabled=true
spring.batch.job.enabled=false

๐Ÿงฑ Employee Entity

@Entity
public class Employee {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  private String name;
  private String email;

  // Getters and Setters
}

๐Ÿ“‚ Sample CSV File (employees.csv)

name,email
John,john@example.com
InvalidUser,invalid-email
Jane,jane@example.com

๐Ÿง  Custom SkipPolicy

public class EmailValidationSkipPolicy implements SkipPolicy {
  @Override
  public boolean shouldSkip(Throwable t, int skipCount) {
    return t instanceof IllegalArgumentException && skipCount < 5;
  }
}

๐Ÿ” ItemProcessor with Validation

public class EmployeeItemProcessor implements ItemProcessor<Employee, Employee> {
  @Override
  public Employee process(Employee employee) throws Exception {
    if (employee.getEmail() == null || !employee.getEmail().contains("@")) {
      throw new IllegalArgumentException("Invalid email: " + employee.getEmail());
    }
    return employee;
  }
}

⚙️ Spring Batch Configuration

@Configuration
public class BatchConfig {

  @Autowired private JobRepository jobRepository;
  @Autowired private PlatformTransactionManager transactionManager;
  @Autowired private EntityManagerFactory entityManagerFactory;

  @Bean
  public Job job() {
    return new JobBuilder("employee-import-job", jobRepository)
      .start(step())
      .incrementer(new RunIdIncrementer())
      .build();
  }

  @Bean
  public Step step() {
    return new StepBuilder("import-step", jobRepository)
      .<Employee, Employee>chunk(5, transactionManager)
      .reader(reader())
      .processor(new EmployeeItemProcessor())
      .writer(writer())
      .faultTolerant()
      .skipPolicy(new EmailValidationSkipPolicy())
      .build();
  }

  @Bean
  public FlatFileItemReader<Employee> reader() {
    return new FlatFileItemReaderBuilder<Employee>()
      .name("employee-reader")
      .linesToSkip(1)
      .resource(new ClassPathResource("employees.csv"))
      .delimited()
      .names("name", "email")
      .targetType(Employee.class)
      .build();
  }

  @Bean
  public JpaItemWriter<Employee> writer() {
    JpaItemWriter<Employee> writer = new JpaItemWriter<>();
    writer.setEntityManagerFactory(entityManagerFactory);
    return writer;
  }
}

๐Ÿš€ REST Controller to Trigger the Job

@RestController
@RequestMapping("/jobs")
public class JobLauncherController {

  @Autowired private JobLauncher jobLauncher;
  @Autowired private Job job;

  @GetMapping("/run-skip-job")
  public String runJob() throws Exception {
    JobParameters params = new JobParametersBuilder()
      .addLong("time", System.currentTimeMillis())
      .toJobParameters();

    jobLauncher.run(job, params);
    return "Job launched!";
  }
}

๐Ÿ“Œ Summary

  • We used SkipPolicy to skip faulty records with invalid emails.
  • Errors are gracefully ignored while keeping track of skipped records.
  • Only valid records are written to the database.
๐Ÿ“บ Want to learn Spring with hands-on videos?
Subscribe to our YouTube channel: Spring Java Lab for practical tutorials on Spring Batch, Boot, and more!