Reputation: 1435
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
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
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
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
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