Search code examples
springspring-bootspring-batchbatch-processingspring-framework-beans

Exception on extending JdbcCursorItemReader


I am new to Spring Batch and trying my hands on to get gain some knowledge on this. I have written the following method to read data from a table but I am getting an exception telling "The SQL query must be provided" although I have provided the query in the method.

    @Configuration
    public class ReadingObjectItemReader extends JdbcCursorItemReader<Person> {

        public DataSource getDataSource() { return dataSource; }        
        @Resource
        public void setDataSource(DataSource dataSource) { super.setDataSource(dataSource); }

        @Autowired
        DataSource dataSource;

        @Bean
        public JdbcCursorItemReader<DimInstitutionalClaim> cursorReader() {
            JdbcCursorItemReader<Person> databaseReader = new JdbcCursorItemReader<>();
            databaseReader.setDataSource(dataSource);
            databaseReader.setSql("select TOP(10) * from dbo.Person ");
            databaseReader.setFetchSize(5);
            databaseReader.setRowMapper(new BeanPropertyRowMapper<>(Person.class));
            return databaseReader;
        }
}

and on the Step I am calling it like this:

@Autowired
ReadingObjectItemReader readingObject;

@Bean
public Step step1() {
    return stepBuilderFactory.get("step1").<Person,Person>chunk(2).reader(readingObject.cursorReader())
            .writer(itemWriter()).listener(promotionListener()).build();
}

when running the above code in my step InputReader I am getting

Caused by: java.lang.IllegalArgumentException: The SQL query must be provided

If I write the above logic in the same class where my job builder and steps are defined and without extending JdbcCursorItemReader like my code below it is working fine.

@Bean
public Step step1() {
    return stepBuilderFactory.get("step1").<Person, Person>chunk(2).reader(itemReader())
            .writer(itemWriter()).listener(promotionListener()).build();
}

@Bean
public ItemReader<Person> itemReader() {
    JdbcCursorItemReader<Person> databaseReader = new JdbcCursorItemReader<>();
    databaseReader.setDataSource(dataSource);
    databaseReader.setSql("select TOP(10) * from dbo.Person ");
    databaseReader.setFetchSize(5);
    databaseReader.setRowMapper(new BeanPropertyRowMapper<>(Person.class));
    return databaseReader;
}

Can some one suggest me what is wrong with my implementation when defining it in a new class and extending it with JdbcCursorItemReader and also is there any other way that I can use JPA queries like findAll() and JPQL on InputReader other than PaginationReaders?


Solution

  • When Spring tries to inject this:

    @Autowired
    ReadingObjectItemReader readingObject;
    

    It sees that ReadingObjectItemReader implements InitializingBean and calls afterPropertiesSet. In this method, there is a check that validates the sql query is provided but it is not the case, and this happen before even arriving to reader(readingObject.cursorReader()).

    Creating a configuration class that extends JdbcCursorItemReader is not correct. A configuration class is used to declare bean definitions. You actually don't need this class, you can declare the reader bean next to your step definition and inject it in the step:

    @Bean
    public JdbcCursorItemReader<DimInstitutionalClaim> cursorReader() {
            JdbcCursorItemReader<Person> databaseReader = new JdbcCursorItemReader<>();
            databaseReader.setDataSource(dataSource);
            databaseReader.setSql("select TOP(10) * from dbo.Person ");
            databaseReader.setFetchSize(5);
            databaseReader.setRowMapper(new BeanPropertyRowMapper<>(Person.class));
            return databaseReader;
    }
    
    @Bean
    public Step step1() {
       return stepBuilderFactory.get("step1").<Person, Person>chunk(2)
            .reader(cursorReader())
            .writer(itemWriter())
            .listener(promotionListener())
            .build();
    }