Home > Enterprise >  JobParameter pass to Processor class in Spring Batch
JobParameter pass to Processor class in Spring Batch

Time:09-14

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.

  • Related