I am trying to store 6 CSV file data in the database. Here I am converting CSV data into another object and going to save it.
To Create the object, I need another field from the rest endpoint as a request body and pass it as a JobParameter.
I need to access that parameter in my processor class. I tried different methods. But I am getting the following errors. Any solution would appreciate.
EL1008E: Property or field 'jobParameters' cannot be found on object of type 'org.springframework.beans.factory.config.BeanExpressionContext' - maybe not public or not valid?
This is my RestEnd Point:
@PostMapping
public void save(@RequestBody DownloadFileRequestDto downloadFileRequestDto) throws IOException {
JobParameters JobParameters = new JobParametersBuilder()
.addString("myParam", downloadFileRequestDto.getMyParam())
.toJobParameters();
try {
JobExecution run = jobLauncher.run(job, JobParameters);
} catch (JobExecutionAlreadyRunningException e) {
throw new RuntimeException(e);
} catch (JobRestartException e) {
throw new RuntimeException(e);
} catch (JobInstanceAlreadyCompleteException e) {
throw new RuntimeException(e);
} catch (JobParametersInvalidException e) {
throw new RuntimeException(e);
}
}
This is my Spring Batch Configuration class:
@Configuration
@EnableBatchProcessing
@AllArgsConstructor
public class SpringBatchConfig {
private JobBuilderFactory jobBuilderFactory;
private StepBuilderFactory stepBuilderFactory;
private UserRepository userRepository;
@Bean
public FlatFileItemReader<InputUser> reader() {
FlatFileItemReader<InputUser> itemReader = new FlatFileItemReader<>();
itemReader.setResource(new FileSystemResource("src/main/resources/users.csv"));
itemReader.setName("csvReader");
itemReader.setLinesToSkip(1);
itemReader.setLineMapper(lineMapper());
return itemReader;
}
private LineMapper<InputUser> lineMapper() {
DefaultLineMapper<InputUser> lineMapper = new DefaultLineMapper<>();
DelimitedLineTokenizer lineTokenizer = new DelimitedLineTokenizer();
lineTokenizer.setDelimiter(",");
lineTokenizer.setStrict(false);
lineTokenizer.setNames("name", "salary");
BeanWrapperFieldSetMapper<InputUser> fieldSetMapper = new BeanWrapperFieldSetMapper<>();
fieldSetMapper.setTargetType(InputUser.class);
lineMapper.setLineTokenizer(lineTokenizer);
lineMapper.setFieldSetMapper(fieldSetMapper);
return lineMapper;
}
@Bean
public Processor processors() {
return new Processor();
}
public RepositoryItemWriter<User> writer(){
RepositoryItemWriter<User> writer = new RepositoryItemWriter<User>();
writer.setRepository(userRepository);
writer.setMethodName("save");
return writer;
}
@Bean
public Step step1(){
return stepBuilderFactory.get("csv-step").<InputUser, User>chunk(500)
.reader(reader())
.processor(processors())
.writer(writer())
.taskExecutor(taskExecutor())
.build();
}
@Bean
public Job job(){
return jobBuilderFactory.get("importUsers")
.flow(step1())
.end().build();
}
public TaskExecutor taskExecutor(){
SimpleAsyncTaskExecutor simpleAsyncTaskExecutor = new SimpleAsyncTaskExecutor();
simpleAsyncTaskExecutor.setConcurrencyLimit(50);
return simpleAsyncTaskExecutor;
}
}
This is my Processor class, where I need access to my job parameters.
@Component
@Scope("step")
public class Processor implements ItemProcessor<InputUser, User> {
@Value("#{jobParameters['myParam']}")
private String fileName;
public Processor() {
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
@Override
public User process(InputUser item) throws Exception {
Random random = new Random();
return new User(random.nextInt(), item.getName(), item.getSalary());
}
}
CodePudding user response:
Remove @Component
and @Scope
from the Processor
class. In the configuration just declare the bean
@Bean
@StepScope
public Processor processors(@Value("#jobParameters['myParam']}") String myParam) {
return new Processor(myParam);
}
Add a constructor in the Processor
class that takes a string.
As is you are creating two beans of Processor
type one in the configuration class and one with @Component
But when defining the step you are using the method in the configuration that is not step scoped and I think spring is not able to inject the value in it.