I am attempting to create a simple Step for a batch process which takes ProductDetail information and other information from the item processor to create and write the new ProductResult to a Mongodb database. I am attempting to use a JdbcPagingItemReader for reading the data from a database. However, when I start the job it fails with an error
java.lang.NullPointerException: Cannot invoke "org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.getJdbcOperations()" because "this.namedParameterJdbcTemplate" is null.
I also tested this with another reader and it works, so it is only the JdbcPagingItemReader that's the issue.
I don't know why the NamedParameterJdbcTemplate is needed since I have provided the select and from values and a configured row mapper.
Here is my code
import com.datacom.mapper.ProductDetailRowMapper;
import com.datacom.model.ProductDetail;
import lombok.RequiredArgsConstructor;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.item.ItemStreamReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.data.MongoItemWriter;
import org.springframework.batch.item.data.builder.MongoItemWriterBuilder;
import org.springframework.batch.item.database.JdbcPagingItemReader;
import org.springframework.batch.item.database.Order;
import org.springframework.batch.item.database.support.OraclePagingQueryProvider;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
@Configuration
@RequiredArgsConstructor
public class ProductDetailConfigStep {
@Value("${db.pageSize}")
int pageSize;
final MongoOperations mongoOperations;
final @Qualifier("productsDataSource") DataSource dataSource;
final PlatformTransactionManager transactionManager;
final JobRepository jobRepository;
@Value("${batch.chunkSize}") int chunkSize;
final ProductResultProcessor productResultProcessor;
public ItemStreamReader<ProductDetail> itemReader() {
JdbcPagingItemReader<ProductDetail> itemReader = new JdbcPagingItemReader<>();
itemReader.setDataSource(productsDataSource);
itemReader.setFetchSize(chunkSize);
OraclePagingQueryProvider queryProvider = new OraclePagingQueryProvider();
queryProvider.setSelectClause(JDBCConstants.SELECT_QUERY);
queryProvider.setFromClause(JDBCConstants.FROM_CLAUSE_QUERY);
itemReader.setRowMapper(new ProductDetailRowMapper());
final Map<String, Order> sortKeys = new HashMap<>();
itemReader.setParameterValues(new HashMap<>());
sortKeys.put("product_id", Order.ASCENDING);
queryProvider.setSortKeys(sortKeys);
itemReader.setQueryProvider(queryProvider);
itemReader.setPageSize(pageSize);
itemReader.setPageSize(chunkSize);
return itemReader;
}
public ItemWriter<ProductResult> itemWriter() {
var writer = new MongoItemWriterBuilder<ProductResult>()
.collection(Documents.PRODUCT_CATALOG_COLLECTION)
.mode(MongoItemWriter.Mode.INSERT)
.template(mongoOperations)
.build();
writer.setTemplate(mongoOperations);
return writer;
}
@Bean("productProcessingDetailStep")
public Step productProcessingDetailStep() {
return new StepBuilder("productCreationStep", jobRepository)
.<ProductDetail, ProductResult>chunk(chunkSize, transactionManager)
.reader(itemReader())
.processor(productResultProcessor)
.writer(itemWriter())
.build();
}
}
What am I missing the configuration of the JdbcPagingItemReader looks fine to me.
new- there will be no autowiring done in the case that you instantiated yourself. If you want Spring to autowire something intoJdbcPagingItemReaderthen let Spring instantiate itItemStreamReader<ProductDetail>useJdbcPagingItemReader<ProductDetail>. That way Spring is able to determine what interfaces there are on the actual class, includingInitialzingBeanso the setup is being done properly. The same applies to your other methods as well.