Deepak Puthraya
Deepak Puthraya

Reputation: 1435

Accessing Job Parameters Spring Batch

I have been struggling with accessing Job Parameters of a job using spring batch. Here is my implementation so far.

@Configuration
@EnableBatchProcessing
@PropertySource("classpath:batch.properties")
public class CSVBatchServiceImpl extends StepExecutionListenerSupport implements CSVBatchService {
    private static final Logger LOGGER = LoggerFactory.getLogger(CSVBatchServiceImpl.class);
    @Autowired
    public JobBuilderFactory jobBuilderFactory;
    @Autowired
    public StepBuilderFactory stepBuilderFactory;

    private QuestionReader questionReader = new QuestionReader();

    @Bean(name = "importQuestionsJob")
    public Job importQuestionsJob() {
        return jobBuilderFactory.get("importQuestionsJob")
                .incrementer(new RunIdIncrementer())
                .flow(step1())
                .end()
                .build();
    }

    @Bean
    public Step step1() {
        return stepBuilderFactory.get("step1")
                .<Question, Question>chunk(2)
                .reader(questionReader.reader())
                .processor(processor())
                .build();
    }

    @Bean
    public QuestionProcessor processor() {
        return new QuestionProcessor();
    }
}

class QuestionReader extends StepExecutionListenerSupport {
    private static final Logger LOGGER = LoggerFactory.getLogger(QuestionReader.class);

    //TODO: remove this
    private static JsonNode getJsonNode(String str) {
        try {
            ObjectMapper mapper = new ObjectMapper();
            return mapper.readTree(str);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Bean
    public FlatFileItemReader<Question> reader() {
        FlatFileItemReader<Question> reader = new FlatFileItemReader<>();
        //TODO get this as a parameter
        reader.setResource(new ClassPathResource("duplicateLabels.csv"));
        reader.setLinesToSkip(1);
        reader.setLineMapper(new DefaultLineMapper<Question>() {{
            setLineTokenizer((new DelimitedLineTokenizer() {{
                setNames(new String[]{"label", "body", "real_answer"});
            }}));
            setFieldSetMapper(new QuestionFieldSetMapper());
        }});
        return reader;
    }

    private static class QuestionFieldSetMapper implements FieldSetMapper<Question> {
        public Question mapFieldSet(FieldSet fieldSet) {
            Question question = new Question();
            question.setLabel(fieldSet.readString(0));
            question.setBody(getJsonNode(fieldSet.readString(1)));
            question.setRealAnswer(getJsonNode(fieldSet.readString(2)));
            return question;
        }
    }
}

I am calling the job like:

JobParameters parameters = new JobParametersBuilder()
        .addLong("time", System.currentTimeMillis())
        .addString("filePath", "file.csv")
        .toJobParameters();
jobLauncher.run(importQuestionsJob, parameters);

How can I go about accessing the filePath parameter inside reader function?

Upvotes: 5

Views: 21984

Answers (4)

Vignesh T I
Vignesh T I

Reputation: 872

One of the ways to access the Job Parameters is to implement StepExecutionListener to your reader Class to make use of its Overridden methods beforeStep and afterStep,

@Override
public void beforeStep(StepExecution stepExecution) {
   String filePath = (String) stepExecution.getJobExecution().getExecutionContext()
        .get("filePath");
}

Upvotes: 0

darefilz
darefilz

Reputation: 701

Another solution that works very well for ItemProcessors, ItemReaders, ItemWriters and so on is the @BeforeStep annotation. It is backed by a StepExecutionListener just like Eugene To mentioned. It is kind of a shortcut for that solution.

An implementation might look like this

@BeforeStep
public void beforeStep(StepExecution stepExecution) {
    JobParameters jobParameters = stepExecution.getJobParameters();

    Long millis = jobParameters.getLong("time");
    String path = jobParameters.getString("filePath");
}

Upvotes: 4

Eugene To
Eugene To

Reputation: 1938

You may add org.springframework.batch.core.listener.JobParameterExecutionContextCopyListener to your Step.

TaskletStep step = stepBuilderFactory.get("my-best-step") .<Item, Item>chunk(10) .reader(myBestReader) .writer(myBestWriter) .listener(new JobParameterExecutionContextCopyListener()) .build();

That Listener will copy JobParameters to ExecutionContext that is available in ItemReader's open and update methods

Upvotes: 1

Sabir Khan
Sabir Khan

Reputation: 10142

You should be able to do ,

@Value("#{jobParameters['filePath']}") String filePath;

In case of any issues, you may try putting your reader in @StepScope.

Upvotes: 2

Related Questions