3

General Information: New to Spring Boot and wanted to test out my JDBC connections via unit tests. I made a simple class to connect to my database and a simple test class to follow up with the proper test case.

Problem: Continuously receiving a java.lang.NullPointerException when performing jdbcTemplate.getDataSource().getConnection(); I am having a hard time understanding why. I tried using different databases, and ensured that I could make a connection with the regular JDBC. I have referred to numerous other questions on Stack Overflow but I have still been stuck on this for the past two days without any progress. I even tried to use different types of DataSource libraries but all of them yield the same result.

Question: How do I solve this? If anyone can also explain why the issue is happening, and why do we need to use the Spring JDBC on an enterprise level, that would be great.


My code:

DatabaseTableService.java

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import com.vertica.jdbc.DataSource;

@RestController
@RequestMapping("/databaseServices")
public class DatabaseTableService {

    private JdbcTemplate jdbcTemplate;
    private DataSource dataSource;


    public void setDataSource(DataSource dataSource) {
        this.dataSource= dataSource;
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }


    @RequestMapping("/testConnection")
    @ResponseBody
    public boolean canConnectToDB() {
        boolean result;
        try {
            jdbcTemplate.getDataSource().getConnection();
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
            result = false;
        }
        return result;
    }

}


beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.company.project"></context:component-scan>

    <mvc:annotation-driven/>

    <bean id="dataSource"
          class="com.vertica.jdbc.DataSource">
        <property name="URL" value="DBURLHERE"/>
        <property name="userID" value="USERIDHERE"/>
        <property name="password" value="PASSWORDHERE"/>
    </bean>






    <bean id="databaseTableService"
          class="com.company.project.services.DatabaseTableService">
        <property name="dataSource" ref="dataSource"></property>
    </bean>


    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix">
            <value>/WEB-INF/</value>
        </property>
        <property name="suffix">
            <value>.jsp</value>
        </property>
    </bean>

</beans>

DatabaseTableServiceTest.java

import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

import com.vertica.jdbc.DataSource;


@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = ApplicationController.class)
@WebAppConfiguration
public class DatabaseTableServiceTest {

    @Autowired
    private WebApplicationContext webApplicationContext;

    private JdbcTemplate jdbcTemplate;
    private MockMvc mockMvc;
    DatabaseTableService databaseTableServiceObject;
    DataSource testDataSource = new DataSource();

    @Before
    public void setUp() throws Exception {
        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
                .build();

        databaseTableServiceObject = new DatabaseTableService();
    }




    @Test
    public void setDataSource() throws Exception {
        databaseTableServiceObject.setDataSource(testDataSource);
    }

    @Test
    public void validateCanConnectToDB() throws Exception {
        Assert.assertTrue(databaseTableServiceObject.canConnectToDB());
    }


    @After
    public void tearDown() throws Exception {
        mockMvc = null;
        databaseTableServiceObject = null;
        testDataSource = null;
    }

}

ApplicationController.java

import org.springframework.boot.*;
import org.springframework.boot.autoconfigure.*;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.*;
import org.springframework.web.bind.annotation.*;


@SpringBootApplication
@ImportResource({"beans.xml"})
@ComponentScan(basePackages = "com.company.project")
public class ApplicationController {

    public static void main(String[] args) throws Exception {

        SpringApplication.run(ApplicationController.class, args);
    }
}

Folder Structure

Folder Structure


Spring Application Context Information Spring Application Context Information

9
  • Is the ApplicationController annotated with SpringBootApplication? If so, did you import the beans.xml resource into it? Add the ApplicationController class. Commented Apr 22, 2016 at 14:38
  • It's not a rule or something, but we usually use auto-configurations when we're using Spring Boot. Commented Apr 22, 2016 at 14:40
  • @AliDehghani added in the ApplicationController class. I tried to import the beans.xml file earlier, but it gave me the error: java.lang.IllegalStateException: Failed to load ApplicationContext Commented Apr 22, 2016 at 14:54
  • Add @ImportResource("classpath:beans.xml") to ApplicationController.. Commented Apr 22, 2016 at 14:56
  • It seems your JdbcTemplate is not @Autowired? Commented Apr 22, 2016 at 14:57

1 Answer 1

2

You are using Spring Boot and next try very hard not to. Remove your beans.xml and the @ImportResource from your ApplicationController (which isn't a controller but your actual application btw, as your service is your actual controller). Also assuming that your ApplicationController is in the same package you can remove the @ComponentScan as well.

Then in your application.properties add the following

spring.datasource.url=<your-url>
spring.datasource.username=<your-username>
spring.datasource.password=<your-password>
spring.datasource.type=com.vertica.jdbc.DataSource

spring.mvc.view.prefix=/WEB-INF/
spring.mvc.view.suffix=.jsp

Spring Boot will create a DataSource and a JdbcTemplate for you, so no need to create that yourself. Just @Autowire the JdbcTemplate in your class.

@RestController
@RequestMapping("/databaseServices")
public class DatabaseTableService {

    private final JdbcTemplate jdbcTemplate;

    @Autowired
    public DatabaseTableService(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate=jdbcTeplate;
    }

    @RequestMapping("/testConnection")
    @ResponseBody
    public boolean canConnectToDB() {
        boolean result;
        try {
            jdbcTemplate.getDataSource().getConnection();
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
            result = false;
        }
        return result;
    }
}

Now your test, it is quite a mess. You are using Spring but are doing things yourself, so not sure what you are trying to achieve there.

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = ApplicationController.class)
@WebAppConfiguration
public class DatabaseTableServiceTest {

    @Autowired
    private WebApplicationContext webApplicationContext;

    private MockMvc mockMvc;
    private DatabaseTableService databaseTableServiceObject;

    @Before
    public void setUp() throws Exception {
        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
                .build();
    }

    @Test
    public void setDataSource() throws Exception {
        databaseTableServiceObject.setDataSource(testDataSource);
    }

    @Test
    public void validateCanConnectToDB() throws Exception {
        Assert.assertTrue(databaseTableServiceObject.canConnectToDB());
    }

}

You can just @Autowiredthe service which is now fully constructed.

Final thing is that your canConnectToDB method is flawed. You are obtaining a connection but are never returning/closing it. So after calling this method for a couple of times your application will stop work as the connection pool will be depleted or your database stops accepting connections.

In short work with the framework instead of against/around the framework. Read the documentation instead of trying to hack your way around it.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you! I am trying to rebuild this without using Spring Boot. I will update you accordingly once I get it working. Sorry for the delayed reply - did not get to work on this project for the past few weeks and didn't want you to think I forgot :)
Thank you again - I took some time to read through the documentation and rebuilt it without Spring Boot.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.