title: Save all skipped records and send those in a mail in spring batch
body: <p>I am new to spring batch and I have come across a scenario, where I have declared one exception in skippable exception, to skip the invalid records detected in item processor. Could you please help me with some possible way through which I can keep track of the all skipped records during the entire job run and at the end using job execution listener or some other way send a mail of all those skipped records.
  Any suggestions would help.</p>
  
  <p>spring-context.xml</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
  &lt;beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:batch="http://www.springframework.org/schema/batch" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch-3.0.xsd
          http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"&gt;
  
      &lt;import resource="classpath:context-datasource.xml" /&gt;
  
  
      &lt;bean
          class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"&gt;
  
          &lt;property name="location"&gt;
              &lt;value&gt;springbatch.properties&lt;/value&gt;
          &lt;/property&gt;
      &lt;/bean&gt;
  
      &lt;bean id="validator"
          class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" /&gt;
  
      &lt;bean id="jobRepository"
          class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean" /&gt;
  
      &lt;bean id="jobLauncher"
          class="org.springframework.batch.core.launch.support.SimpleJobLauncher"&gt;
          &lt;property name="jobRepository" ref="jobRepository" /&gt;
      &lt;/bean&gt;
  
  
      &lt;!-- ItemReader which reads from database and returns the row mapped by 
          rowMapper --&gt;
      &lt;bean id="databaseItemReader"
          class="org.springframework.batch.item.database.JdbcCursorItemReader"&gt;
  
          &lt;property name="dataSource" ref="dataSource" /&gt;
  
          &lt;property name="sql" value="SELECT * FROM employee" /&gt;
  
          &lt;property name="rowMapper"&gt;
              &lt;bean class="com.sample.springbatch.jdbc.EmployeeRowMapper" /&gt;
          &lt;/property&gt;
  
      &lt;/bean&gt;
  
  
      &lt;!-- ItemWriter writes a line into output flat file --&gt;
      &lt;bean id="databaseItemWriter"
          class="org.springframework.batch.item.database.JdbcBatchItemWriter"&gt;
  
          &lt;property name="dataSource" ref="dataSource" /&gt;
  
          &lt;property name="sql"&gt;
              &lt;value&gt;
                  &lt;![CDATA[        
                      insert into actemployee(empId, firstName, lastName,additionalInfo) 
                      values (?, ?, ?, ?)
                  ]]&gt;
              &lt;/value&gt;
          &lt;/property&gt;
  
          &lt;property name="itemPreparedStatementSetter"&gt;
              &lt;bean class="com.sample.springbatch.jdbc.EmployeePreparedStatementSetter" /&gt;
          &lt;/property&gt;
  
      &lt;/bean&gt;
  
  
  
  
      &lt;!-- Optional ItemProcessor to perform business logic/filtering on the input 
          records --&gt;
      &lt;bean id="itemProcessor" class="com.sample.springbatch.EmployeeItemProcessor"&gt;
          &lt;property name="validator" ref="validator" /&gt;
      &lt;/bean&gt;
  
      &lt;!-- Step will need a transaction manager --&gt;
      &lt;bean id="transactionManager"
          class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" /&gt;
  
  
      &lt;bean id="recordSkipListener" class="com.sample.springbatch.RecordSkipListener" /&gt;
  
      &lt;!-- Actual Job --&gt;
      &lt;batch:job id="employeeToActiveEmployee"&gt;
          &lt;batch:step id="step1"&gt;
              &lt;batch:tasklet transaction-manager="transactionManager"&gt;
                  &lt;batch:chunk reader="databaseItemReader" writer="databaseItemWriter"
                      processor="itemProcessor" commit-interval="10" skip-limit="500"&gt;
                      &lt;batch:skippable-exception-classes&gt;
                          &lt;batch:include
                              class="javax.validation.ValidationException" /&gt;
                      &lt;/batch:skippable-exception-classes&gt;
                  &lt;/batch:chunk&gt;
  
              &lt;/batch:tasklet&gt;
              &lt;batch:listeners&gt;
                  &lt;batch:listener ref="recordSkipListener" /&gt;
              &lt;/batch:listeners&gt;
          &lt;/batch:step&gt;
      &lt;/batch:job&gt;
  
  
      &lt;!-- Email API bean configuarion --&gt;
  &lt;/beans&gt;
  
  
  Processor.java
          public class EmployeeItemProcessor implements ItemProcessor&lt;Employee, ActiveEmployee&gt; {
  
      private Validator validator;
  
      public Validator getValidator() {
          return validator;
      }
  
      public void setValidator(Validator validator) {
          this.validator = validator;
      }
  
      @Override
      public ActiveEmployee process(Employee employee) throws Exception {
          BindingResult results = BindAndValidate(employee);
          if (results.hasErrors()) {
              buildValidationException(results);
          }
          System.out.println("Processing employee object:" + employee);
          ActiveEmployee activeEmployee = new ActiveEmployee(employee.getEmpId(), employee.getFirstName(),
                  employee.getLastName(), "This is additional info");
          return activeEmployee;
  
      }
  
      private BindingResult BindAndValidate(Employee employee) {
          DataBinder binder = new DataBinder(employee);
          binder.setValidator(validator);
          binder.validate();
          return binder.getBindingResult();
  
      }
  
      private void buildValidationException(BindingResult results) {
          StringBuilder msg = new StringBuilder();
          for (ObjectError error : results.getAllErrors()) {
              msg.append("-*-*-*- \n" + error.toString() + "-*-*-*- \n");
          }
          throw new ValidationException(msg.toString());
      }
  
  }
  </code></pre>
  
  <p>Thanks!!</p>