0

I need to attached the ReadCount to the file footer, I dont know why the JobExecution in writeFooter method is null.

I found this and according to the comments I should be able to write this information to the footer: Accessing the ExecutionContext values in HeaderCallBack in Spring Batch

public class Footer implements FlatFileFooterCallback {

    private final String footer;
    private String julianDate;
    private StepExecution stepExecution;

    @AfterStep
    public void afterStep(StepExecution stepExecution) {
        ExecutionContext je = stepExecution.getJobExecution().getExecutionContext();
        je.putLong("writeCount", stepExecution.getReadCount());
    }

    @BeforeStep
    public void beforeStep(StepExecution stepExecution) {
        this.stepExecution = stepExecution;
    }

    // TODO: NEED TO REPLACE COUNT WITH NUMBER OF RECORDS IN FILE
    public Footer(){
        this.julianDate = createJulianDate();
        this.footer = "";
    }

    @Override
    public void writeFooter(Writer writer) throws IOException {
        JobExecution jobExecution = this.stepExecution.getJobExecution();
        ExecutionContext jobContext = jobExecution.getExecutionContext();
        writer.write(footer);
    }

I tried to implement StepExecutionListener and the stepExecution is null inside the writeFooter method.

public class Footer implements FlatFileFooterCallback, StepExecutionListener {

    private final String footer;
    private String julianDate;
    private StepExecution stepExecution;

    // TODO: NEED TO REPLACE COUNT WITH NUMBER OF RECORDS IN FILE
    public Footer(){
        this.julianDate = createJulianDate();
        this.footer = "";
    }

    @Override
    public void beforeStep(StepExecution stepExecution) {
        this.stepExecution = stepExecution;
    }

    @Override
    public ExitStatus afterStep(StepExecution stepExecution) {
        System.out.println(stepExecution.getReadCount());
        System.out.println("END");
        return ExitStatus.COMPLETED;
    }

    @Override
    public void writeFooter(Writer writer) throws IOException {
        writer.write("Foot - number of items written: " + stepExecution.getWriteCount());
        writer.write(footer);
    }
PAA
  • 1
  • 46
  • 174
  • 282

1 Answers1

1

You can declare the footer callback as a step scoped bean and inject the write count from the step execution context using a SpEL expression. Here is an example:

import java.util.Arrays;

import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
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.core.configuration.annotation.StepScope;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.file.FlatFileFooterCallback;
import org.springframework.batch.item.file.builder.FlatFileItemWriterBuilder;
import org.springframework.batch.item.file.transform.PassThroughLineAggregator;
import org.springframework.batch.item.support.ListItemReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.FileSystemResource;

@Configuration
@EnableBatchProcessing
public class MyJob {

    @Autowired
    private JobBuilderFactory jobs;

    @Autowired
    private StepBuilderFactory steps;

    @Bean
    public ItemReader<Integer> itemReader() {
        return new ListItemReader<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
    }

    @Bean
    public ItemWriter<Integer> itemWriter() {
        return new FlatFileItemWriterBuilder<Integer>()
                .name("fileWriter")
                .resource(new FileSystemResource("numbers.txt"))
                .lineAggregator(new PassThroughLineAggregator<>())
                .footerCallback(footerCallback(null))
                .build();
    }

    @Bean
    @StepScope
    public FlatFileFooterCallback footerCallback(@Value("#{stepExecutionContext['fileWriter.written']}") Integer writeCount) {
        return writer -> writer.write("total items: " + writeCount);
    }

    @Bean
    public Step step() {
        return steps.get("step")
                .<Integer, Integer>chunk(5)
                .reader(itemReader())
                .writer(itemWriter())
                .build();
    }

    @Bean
    public Job job() {
        return jobs.get("job")
                .start(step())
                .build();
    }

    public static void main(String[] args) throws Exception {
        ApplicationContext context = new AnnotationConfigApplicationContext(MyJob.class);
        JobLauncher jobLauncher = context.getBean(JobLauncher.class);
        Job job = context.getBean(Job.class);
        jobLauncher.run(job, new JobParameters());
    }

}

This generates a file named numbers.txt with the following content:

1
2
3
4
5
6
7
8
9
10
total items: 10
Mahmoud Ben Hassine
  • 28,519
  • 3
  • 32
  • 50