Listening to Skip events using SkipListener

In this post under Spring Batch, I will explain with an example of how to listen to skip events.

The skip events are generated during reading, writing, and processing of records.

We can listen to these skip events with the help of org.springframework.batch.core.SkipListener interface.

The SkipListener interface has three methods
1) onSkipInProcess
purpose –> provide implementation for this method to listen to skip events during processing of a record.
parameters –> record that caused the exception and the exception itself

2) onSkipInRead
purpose –> provide implementation for this method to listen to skip events during reading of a record.
parameters –> the exception

3) onSkipInWrite
purpose –> provide implementation for this method to listen to skip events during writing of a record.
parameters –> record that caused the exception and the exception itself

Below is implementation of SkipListener interface

MySkipListener


1  package package25;
2  
3  import org.springframework.batch.core.SkipListener;
4  import org.springframework.batch.item.file.FlatFileParseException;
5  
6  public class MySkipListener implements SkipListener {
7   @Override
8   public void onSkipInProcess(Employee employee, Throwable throwable) {
9   }
10 
11  @Override
12  public void onSkipInRead(Throwable throwable) {
13      if(throwable instanceof FlatFileParseException) {
14          FlatFileParseException flatFileParseException = (FlatFileParseException) throwable;
15          String message = flatFileParseException.getMessage() + "-" + flatFileParseException.getLineNumber();
16          System.out.println(message);
17      }
18  }
19 
20  @Override
21  public void onSkipInWrite(Employee employee, Throwable throwable) {
22  }
23 }

In the above code, I have provided an implementation of onSkipInRead method.

The method prints the exception message and the line number in the file where this exception occurred.

Now we need to integrate this bean with our Spring Batch Job. The xml snippet is as shown below

XML snippet


1   <bean id="mySkipListener" class="package25.MySkipListener"/>
2   
3   <batch:job id="importEmployees">
4       <batch:step id="readWriteEmployees">
5           <batch:tasklet>
6               <batch:chunk reader="reader" writer="writer" commit-interval="50" skip-limit="200">
7                   <batch:skippable-exception-classes>
8                       <batch:include class="org.springframework.batch.item.file.FlatFileParseException"/>
9                   </batch:skippable-exception-classes>
10              </batch:chunk>
11              <batch:listeners>
12                  <batch:listener ref="mySkipListener"/>
13              </batch:listeners>
14          </batch:tasklet>
15      </batch:step>
16  </batch:job>

In the above xml code, at line 1 I have created a bean definition for MySkipListener with id “mySkipListener”.

Next at line 12, we refer to mySkipListener in “batch:listener” element.

In this way we integrate listener bean with the job.

Below is the complete xml configuration for your reference

XML configuration


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:batch="http://www.springframework.org/schema/batch"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                        http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch.xsd">
    
    <bean id="employee" class="package25.Employee" scope="prototype"/>
    
    <bean id="reader" class="org.springframework.batch.item.file.FlatFileItemReader">
        <property name="resource" value="file:FileInput8.txt"/>
        <property name="lineMapper">
            <bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
                <property name="lineTokenizer">
                    <bean class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
                        <property name="names" value="id,name,status,salary"/>
                    </bean>
                </property>
                <property name="fieldSetMapper">
                    <bean class="org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper">
                        <property name="prototypeBeanName" value="employee"/>
                    </bean>
                </property>
            </bean>
        </property> 
    </bean>
    
    <bean id="writer" class="org.springframework.batch.item.file.FlatFileItemWriter">
        <property name="resource" value="file:FileOutput.txt"/>
        <property name="lineAggregator">
            <bean class="org.springframework.batch.item.file.transform.DelimitedLineAggregator">
                <property name="fieldExtractor">
                    <bean class="org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor">
                        <property name="names" value="id,name,status,salary"/>
                    </bean>
                </property>
            </bean>
        </property>
    </bean>
    
    <bean id="mySkipListener" class="package25.MySkipListener"/>
    
    <batch:job id="importEmployees">
        <batch:step id="readWriteEmployees">
            <batch:tasklet>
                <batch:chunk reader="reader" writer="writer" commit-interval="50" skip-limit="200">
                    <batch:skippable-exception-classes>
                        <batch:include class="org.springframework.batch.item.file.FlatFileParseException"/>
                    </batch:skippable-exception-classes>
                </batch:chunk>
                <batch:listeners>
                    <batch:listener ref="mySkipListener"/>
                </batch:listeners>
            </batch:tasklet>
        </batch:step>
    </batch:job>
    
    <bean id="transactionManager" class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />
    
    <bean id="jobRepository" class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean">
        <property name="transactionManager" ref="transactionManager"/>
    </bean>
    
    <bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
        <property name="jobRepository" ref="jobRepository"/>
    </bean>
</beans>

Check these products on Amazon

Leave a Reply