spring-bootspring-batchjdbctemplate

Cannot invoke "org.springframework.jdbc.core.JdbcTemplate.update(String, Object[])" because "this.jdbcTemplate" is null


I have a spring batch project and i need to integrate a jdbcTemplate in the JobExecutionListener. So i configured my datasource and jdbcTemplate as shown bellow:

import java.util.Objects;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.core.JdbcTemplate;

import com.zaxxer.hikari.HikariDataSource;

@Configuration
public class JdbcTemplateConfig {

    @Bean("JdbcBI")
    @Qualifier("JdbcBI")
    public JdbcTemplate jdbcTemplate() {
        final JdbcTemplate template = new JdbcTemplate();
        template.setDataSource(dataSource());
        return template;
    }
    @Bean
    @ConfigurationProperties("spring.datasource.bi")
    public DataSourceProperties biDataSourceProperties() {
        return new DataSourceProperties();
    }
    
    @Bean
    @Qualifier("bi")
    @Primary
    public DataSource dataSource() {
        HikariDataSource ds = new HikariDataSource();
        ds.setJdbcUrl(Objects.requireNonNull(biDataSourceProperties().getUrl()));
        ds.setUsername(Objects.requireNonNull(biDataSourceProperties().getUsername()));
        ds.setPassword(Objects.requireNonNull(biDataSourceProperties().getPassword()));
        ds.setDriverClassName(Objects.requireNonNull(biDataSourceProperties().getDriverClassName()));
        ds.setAutoCommit(true);
        ds.setMaximumPoolSize(20);
        return ds;
    }
}

knowing that i declared my dataSource properties in the application.properties file:

spring.datasource.bi.url=jdbc:sqlserver://localhost;databaseName=SQLBI;useBulkCopyForBatchInsert=true;integratedSecurity=false;encrypt=false;trustServerCertificate=false
spring.datasource.bi.username=mongo_user
spring.datasource.bi.password=Azerty
spring.datasource.bi.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver
spring.datasource.hikari.data-source-properties.encrypt=false

and I'm using Spring boot version 3.2.2:

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-batch</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>com.microsoft.sqlserver</groupId>
            <artifactId>mssql-jdbc</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.batch</groupId>
            <artifactId>spring-batch-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

Yet, when i use the jdbcTemplate in the JobListener, it throws this error:

java.lang.NullPointerException: Cannot invoke "org.springframework.jdbc.core.JdbcTemplate.update(String, Object[])" because "this.jdbcTemplate" is null

and here is my JobExecutionListener class:

import org.apache.commons.lang3.StringUtils;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobExecutionListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

@Component
public class CustomJobExecutionListener implements JobExecutionListener {
    
    @Autowired
    JdbcTemplate jdbcTemplate;


    @Override
    public void afterJob(JobExecution jobExecution) {
        String query = "INSERT INTO tabler (Val, Vab, Vai) VALUES ('1', '2', '3')";
        jdbcTemplate.update(query);
    }
}

Solution

  • You have declared:

    @Bean("JdbcBI")
    @Qualifier("JdbcBI")
    public JdbcTemplate jdbcTemplate() {
        final JdbcTemplate template = new JdbcTemplate();
        template.setDataSource(dataSource());
        return template;
    }
    

    And when you are injecting the bean to another service you have to do it with @Qualifier:

    @Autowired
    @Qualifier("JdbcBI")
    private JdbcTemplate jdbcTemplate;