Reputation: 1735
I have a use case where I need to dynamically change the resource, the column names, positions of the columns, and other stuff in the Spring Batch configuration bean. The jobs will be launched from a JobLauncher
.
I have constructed the following:
@Configuration
@EnableBatchProcessing
public class BatchConfiguration {
public JobBuilderFactory jobBuilderFactory;
public StepBuilderFactory stepBuilderFactory;
//these are the properties i need to dynamically change
private String[] names;
private Resource inputResource;
private String[] positions;
private String tableName;
private String columnNames;
private String values;
@Autowired
public void setJobBuilderFactory(JobBuilderFactory jobBuilderFactory) {
this.jobBuilderFactory = jobBuilderFactory;
}
@Autowired
public void setStepBuilderFactory(StepBuilderFactory stepBuilderFactory) {
this.stepBuilderFactory = stepBuilderFactory;
}
@Bean
BatchConfigurer configurer(@Qualifier("prestagingJpaDataSource") DataSource dataSource){
return new DefaultBatchConfigurer(dataSource);
}
@Bean
public FlatFileItemReader<String[]> reader() {
return new FlatFileItemReaderBuilder<String[]>()
.name("hacReader")
//put file here
.resource(inputResource)
.lineMapper(new DefaultLineMapper<String[]>() {{
setLineTokenizer(new DelimitedLineTokenizer() {{
//put column names here
setNames(names);
}});
//put column positions here
setFieldSetMapper(fieldSet -> positions);
}})
.build();
}
//this is obviously wrong, as i would need to use an ItemPreparedStatementSetter
@Bean
public JdbcBatchItemWriter<String[]> writer(DataSource dataSource) {
return new JdbcBatchItemWriterBuilder<String[]>()
.itemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<>())
.sql("INSERT INTO " + tableName + " (" + columnsNames + ") VALUES (" + values)
.dataSource(dataSource)
.build();
}
@Bean
public Job importUserJob(JobCompletionNotificationListener listener, Step step1) {
return jobBuilderFactory.get("importUserJob")
.incrementer(new RunIdIncrementer())
.listener(listener)
.flow(step1)
.end()
.build();
}
@Bean
public Step step1(JdbcBatchItemWriter<String[]> writer) {
return stepBuilderFactory.get("step1")
.<String[], String[]> chunk(10)
.reader(reader())
//.processor(processor())
.writer(writer)
.build();
}
}
Is something like this possible with Spring Batch? These are properties that will vary always so I absolutely cannot have any hard-coded values.
If yes, then what would I need to do to make them work?
Upvotes: 1
Views: 4568
Reputation: 31745
You can do that by passing these properties as job parameters (those are best passed as non-identifying job parameters in this case) and late-bind them in your reader at runtime. Here is an example:
@Bean
@StepScope
public ItemReader<String[]> itemReader(
@Value("#{jobParameters['fileName']}") String fileName,
@Value("#{jobParameters['columnNames']}") String columnNames
) {
return new FlatFileItemReaderBuilder<String[]>()
.name("hacReader")
//put file here
.resource(new FileSystemResource(fileName))
.lineMapper(new DefaultLineMapper<String[]>() {{
setLineTokenizer(new DelimitedLineTokenizer() {{
//put column names here
setNames(columnNames.split(","));
}});
}})
.build();
}
With this setup, the reader will be dynamically configured with the fileName
and columnNames
specified as job parameters:
JobParameters jobParameters = new JobParametersBuilder()
.addString("fileName", "/path/to/input/file")
.addString("columnNames", "column1,column2,column5")
.toJobParameters();
Hope this helps.
Upvotes: 2