title: How to combine multiple listeners (step, read, process, write and skip) in spring batch
body: <p>The aim of this operation is to track the lines or items that are being read/processed/written in a spring batch job with multiple steps.</p>
  
  <p>I have created a listener that implements these interfaces : <code>StepExecutionListener, SkipPolicy, ItemReadListener, ItemProcessListener, ItemWriteListener</code></p>
  
  <pre class="lang-java prettyprint-override"><code>@Component
  public class GenericListener implements StepExecutionListener, SkipPolicy, ItemReadListener, ItemProcessListener, ItemWriteListener {
      private Log logger = LogFactory.getLog(getClass());
      private JobExecution jobExecution;
      private int numeroProcess = 0;
      private int currentReadIndex = 0;
      private int currentProcessIndex = 0;
      private int currentWriteIndex = 0;
  
      @Override
      public void beforeRead() throws Exception {
          log.info(String.format("[read][line : %s]", currentReadIndex));
          currentReadIndex++;
      }
      @Override
      public void afterRead (Object o) throws Exception {
          log.info("Ligne correct");
      }
      @Override
      public void onReadError (Exception e) throws Exception {
          jobExecution.stop();
      }
      @Override
      public boolean shouldSkip (Throwable throwable, int i) throws SkipLimitExceededException {
          String err = String.format("Erreur a la ligne %s | message %s | cause %s | stacktrace %s", numeroProcess, throwable.getMessage(), throwable.getCause().getMessage(), throwable.getCause().getStackTrace());
          log.error(err);
          return true;
      }
      @Override
      public void beforeProcess (Object o) {
          log.debug(String .format("[process:%s][%s][Object:%s]", numeroProcess++, o.getClass(), o.toString()));
          currentProcessIndex++;
      }
      @Override
      public void afterProcess (Object o, Object o2) { }
      @Override
      public void onProcessError (Object o, Exception e) {
          String err = String.format("[ProcessError at %s][Object %s][Exception %s][Trace %s]", currentProcessIndex, o.toString(), e.getMessage(), e.getStackTrace());
          log.error(err);
          jobExecution.stop();
      }
      @Override
      public void beforeWrite (List list) {
          log.info(String .format("[write][chunk number:%s][current chunk size %s]", currentWriteIndex, list != null ? list.size() : 0));
          currentWriteIndex++;
      }
      @Override
      public void afterWrite (List list) { }
      @Override
      public void onWriteError (Exception e, List list) {
          jobExecution.stop();
      }
      @Override
      public void beforeStep(StepExecution stepExecution) {
          jobExecution = stepExecution.getJobExecution();
          currentReadIndex = 0;
          currentProcessIndex = 0;
          currentWriteIndex = 0;
      }
      @Override
      public ExitStatus afterStep(StepExecution stepExecution) {
          return null;
      }
  }
  </code></pre>
  
  <p>The job definition (<code>CustomJobListener</code> is a simple class that extends <code>JobExecutionListenerSupport</code>) </p>
  
  <pre class="lang-java prettyprint-override"><code>public class BatchConfiguration {
      @Autowired
      public JobBuilderFactory jobs;
  
      @Bean
      public Job job(CustomJobListener listener,
                       @Qualifier("step1") Step step1,
                       @Qualifier("step2") Step step2,
                       @Qualifier("step3") Step step3) {
          return jobs.get("SimpleJobName")
                  .incrementer(new RunIdIncrementer())
                  .preventRestart()
                  .listener(listener)
                  .start(step1)
                  .next(step2)
                  .next(step3)
                  .build();
      }
  }
  </code></pre>
  
  <p>The step definition (all three steps have the same definition, only the read/processor/writer changes)</p>
  
  <pre class="lang-java prettyprint-override"><code>@Component
  public class StepControleFormat {
      @Autowired
      private StepOneReader reader;
      @Autowired
      private StepOneProcessor processor;
      @Autowired
      private StepOneWriter writer;
      @Autowired
      private ConfigAccess configAccess;
      @Autowired
      private GenericListener listener;
      @Autowired
      public StepBuilderFactory stepBuilderFactory;
  
      @Bean
      @JobScope
      @Qualifier("step1")
      public Step stepOne() throws StepException {
          return stepBuilderFactory.get("step1")
                  .&lt;StepOneInput, StepOneOutput&gt;chunk(configAccess.getChunkSize())
                  .listener((ItemProcessListener&lt;? super StepOneInput, ? super StepOneOutput&gt;) listener)
                  .faultTolerant()
                  .skipPolicy(listener)
                  .reader(reader.read())
                  .processor(processor.compose())
                  .writer(writer)
                  .build();
      }
  }
  </code></pre>
  
  <p>Now the problem is that methods <code>beforeStep(StepExecution stepExecution)</code> and <code>afterStep(StepExecution stepExecution)</code> are not fired, but all other methods in <code>GenericListener</code> are correctly fired when their respective events occur.</p>
  
  <p>I tried using <code>listener((StepExecutionListener)listener)</code> instead of <code>listener((ItemProcessListener&lt;? super StepOneInput, ? super StepOneOutput&gt;) listener)</code> but the latter returns <code>AbstractTaskletStepBuiler</code> and then I cant use <code>reader</code>, <code>processor</code> or <code>writer</code>.</p>
  
  <p><strong>Update</strong> : My spring boot version is : v1.5.9.RELEASE</p>