Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I configure Spring Batch StepScope using java-based configuration?

I'm setting up a job server using Spring Batch. My JdbcCursorItemReader needs to be configured with sql that changes on a per-job run basis. Because the sql changes, I want the reader to have @StepScope so I don't need to worry about sql statefulness.

So I've setup a class like this:

public class ParameterSettingJdbcCursorItemReader extends JdbcCursorItemReader implements StepExecutionListener {

    @Override
    public void beforeStep(StepExecution stepExecution) {

        JobParameters jobParameters = stepExecution.getJobParameters();

        if (jobParameters != null) {
            List<Object> args = new ArrayList<Object>();
            for (JobParameter jobParameter : jobParameters.getParameters().values()) {
                args.add(jobParameter.getValue());
            }

            Object[] arrayArgs = args.toArray(new Object[args.size()]);
            String sql = String.format(getSql(), arrayArgs);
            setSql(sql);
        }
    }

    @Override
    public ExitStatus afterStep(StepExecution stepExecution) {
        return null;
    }
}

The idea is that I pass sql parameters to the object via JobParameters and use String.format to fill in the dynamically-changing sql.

I am using Java-based configuration throughout my server. My bean for one instance of my ItemReader looks like:

@Bean
@StepScope
public ItemReader<MyInputObject> myInputObjectItemReader() {
    ParameterSettingJdbcCursorItemReader itemReader = new ParameterSettingJdbcCursorItemReader();
    itemReader.setDataSource(myDataSource());
    itemReader.setSql("SELECT * FROM my_table WHERE date = '%1$s'");
    itemReader.setRowMapper(myInputObjectMapper);
    return itemReader;
}

When I start up my server and run the Spring Batch job, I get this error: java.lang.IllegalStateException: No Scope registered for scope 'step'

I've read elsewhere that in order to be able to use StepScope, one needs to first add it to the xml app configuration like this : <bean class="org.springframework.batch.core.scope.StepScope" />

But since I'm using Java-based configuration, that's not an option.

So how do I register the StepScope via a Java-based config? I've tried this:

@Bean
public org.springframework.batch.core.scope.StepScope stepScope() {
    return new org.springframework.batch.core.scope.StepScope();
}

... but when I do I get all sorts of NPEs during app startup on beans that have no relation to StepScope.

Thanks in advance.

like image 993
Samuel Dupont Avatar asked Oct 02 '22 11:10

Samuel Dupont


2 Answers

You have to register the scope with the ApplicationContext. Normally that would be done for you when you use @EnableBatchProcessing. Did you do that (add that annotation to one of your @Configurations)?

like image 78
Dave Syer Avatar answered Oct 13 '22 10:10

Dave Syer


+1 to Dave's point about using @EanbleBatchProcesssing. That will add a StepScope to your context. However, your code still won't work once you've done that because you're returning an ItemReader for "myInputObjectItemReader" instead of ParameterSettingJdbcCursorItemReader. See the issue here for details on why that matters: Spring-batch @BeforeStep does not work with @StepScope

like image 32
Michael Minella Avatar answered Oct 13 '22 10:10

Michael Minella