16

I'm new to Spring and to J2EE in general. I'm having trouble using JDBC template with Spring Boot autoconfiguration.

What I did was I took the example of RESTful web service provided here and decided to extend it to use JDBC template relational database access. Unfortunately another example provided cannot be useful because the only difficulty which is providing dataSource from xml beans file is not considered.

What I tried to solve the issue:

  1. Using DAO Impl class as extend of different implementations from Spring.
  2. Adding to beans file.
  3. Using different DataSource classes (eg DriverManagerDataSource).
  4. Trying to autowire just a simple attribute in a different class (something less complex then data source).
  5. On the beggining I just written DAO class, but then I though that maybe it is possible to autowire datasource only if it implements an interface, tryed it, didn't help.

I tryed everything I found on Stack or Google. Most examples are seriously outdated or unanswered or have nothing to do with Spring Boot Autoconfiguration et cetera.

I keep getting Property 'dataSource' is required error, after struggling if finally managed to link the application-config.xml file with beans, but can't manage to autowire the datasource for JDBC.

I'm desperade to finish it and seriously blocked, out of ideas, I would be greatfull if somebody could provide a recent example that works with Spring Boot Autoconfigurations, beans in XML find, autowired datasource for JDBC.

Or at least some ideas, clues, even how to look for it, because I'm even out of keywords for google'ing.

Thanks!

enter image description here

Spring Application class.

package ws;

import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;

@Configuration
@ComponentScan
@ImportResource("classpath:spring/application-config.xml")
@EnableAutoConfiguration
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

Web Service class.

package ws;

import dao.UserDAOImpl;
import model.User;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestWS {
    @RequestMapping("/greeting")
    public User greeting(@RequestParam(value="name", defaultValue="World") String name) {
    return new User("ubububu", "661331555", 0);
    }
    @RequestMapping("/create")
    public String initialize() {
        UserDAOImpl users = new UserDAOImpl();
        users.init();
        return "seems ok";
    }
}

DAO interface

package dao;

import model.User;

public interface UserDAO {
    public void insert(User usr);
    public void init();
    public User select(int id);
}

DAO implementation

package dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.stereotype.Repository;

import model.User;
import dao.UserDAO;

@Repository
public class UserDAOImpl implements UserDAO {
    private JdbcTemplate jdbcTemplate;
    private DriverManagerDataSource dataSource;
    @Autowired
    public void setDataSource(DriverManagerDataSource dataSource) {
        this.dataSource = dataSource;
    }

    public void insert(User usr) {
        String sql = "INSERT INTO USER " +
                "(USR_ID, EMAIL, PHONE) VALUES (?, ?, ?)";

        this.jdbcTemplate = new JdbcTemplate(dataSource);
        jdbcTemplate.execute(sql);
    }

    public void init() {
        String sql = "CREATE TABLE USER (USR_ID INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,EMAIL VARCHAR(30) NOT NULL,PHONE VARCHAR(15) NOT NULL)";
        this.jdbcTemplate = new JdbcTemplate(dataSource);
        jdbcTemplate.execute(sql);
    }
}

Data model

package model;

public class User {
    private String email;
    private String phone;
    private int id;
    public User(String email, String phone, int id) {
        this.email = email;
        this.phone = phone;
        this.id = id;
    }
    public int getUsrId(){
        return this.id;
    }
    public String getUsrEmail() {
        return this.email;
    }
    public String getUsrPhone() {
        return this.phone;
    }
}

Configuration bean file

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans" 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/context http://www.springframework.org/schema/context/spring-context.xsd">
    <import resource="Spring-User.xml" />-->
    <context:component-scan base-package="ws"/>
    <bean id="ds" 
         class="org.springframework.jdbc.datasource.DriverManagerDataSource">

        <property name="driverClassName" value="org.springframework.jdbc.core.JdbcTemplate" />
        <property name="url" value="jdbc:mysql://localhost/:3306/databasename" />
        <property name="username" value="root" />
        <property name="password" value="password" />
    </bean>
    <bean id="UserDAOprovider" class="dao.UserDAOImpl">
        <property name="dataSource" ref="ds" />
    </bean> 

</beans>

Error message:

ERROR [dispatcherServlet] - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.IllegalArgumentException: Property 'dataSource' is required] with root cause
java.lang.IllegalArgumentException: Property 'dataSource' is required
    at org.springframework.jdbc.support.JdbcAccessor.afterPropertiesSet(JdbcAccessor.java:135) ~[spring-jdbc-4.0.8.RELEASE.jar!/:4.0.8.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.<init>(JdbcTemplate.java:169) ~[spring-jdbc-4.0.8.RELEASE.jar!/:4.0.8.RELEASE]
    at dao.UserDAOImpl.init(UserDAOImpl.java:66) ~[demo3-0.0.1-SNAPSHOT.jar!/:na]
    at ws.TestWS.initialize(TestWS.java:30) ~[demo3-0.0.1-SNAPSHOT.jar!/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.6.0_33]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) ~[na:1.6.0_33]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.6.0_33]
    at java.lang.reflect.Method.invoke(Method.java:622) ~[na:1.6.0_33]
    at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:215) ~[spring-web-4.0.8.RELEASE.jar!/:4.0.8.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132) ~[spring-web-4.0.8.RELEASE.jar!/:4.0.8.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104) ~[spring-webmvc-4.0.8.RELEASE.jar!/:4.0.8.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:749) ~[spring-webmvc-4.0.8.RELEASE.jar!/:4.0.8.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:689) ~[spring-webmvc-4.0.8.RELEASE.jar!/:4.0.8.RELEASE]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83) ~[spring-webmvc-4.0.8.RELEASE.jar!/:4.0.8.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:938) ~[spring-webmvc-4.0.8.RELEASE.jar!/:4.0.8.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870) ~[spring-webmvc-4.0.8.RELEASE.jar!/:4.0.8.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961) ~[spring-webmvc-4.0.8.RELEASE.jar!/:4.0.8.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852) ~[spring-webmvc-4.0.8.RELEASE.jar!/:4.0.8.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:620) ~[tomcat-embed-core-7.0.57.jar!/:7.0.57]
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837) ~[spring-webmvc-4.0.8.RELEASE.jar!/:4.0.8.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:727) ~[tomcat-embed-core-7.0.57.jar!/:7.0.57]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303) ~[tomcat-embed-core-7.0.57.jar!/:7.0.57]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) ~[tomcat-embed-core-7.0.57.jar!/:7.0.57]
    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77) ~[spring-web-4.0.8.RELEASE.jar!/:4.0.8.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.0.8.RELEASE.jar!/:4.0.8.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) ~[tomcat-embed-core-7.0.57.jar!/:7.0.57]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) ~[tomcat-embed-core-7.0.57.jar!/:7.0.57]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220) ~[tomcat-embed-core-7.0.57.jar!/:7.0.57]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122) ~[tomcat-embed-core-7.0.57.jar!/:7.0.57]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:503) ~[tomcat-embed-core-7.0.57.jar!/:7.0.57]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170) ~[tomcat-embed-core-7.0.57.jar!/:7.0.57]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103) ~[tomcat-embed-core-7.0.57.jar!/:7.0.57]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116) ~[tomcat-embed-core-7.0.57.jar!/:7.0.57]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:421) ~[tomcat-embed-core-7.0.57.jar!/:7.0.57]
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1070) ~[tomcat-embed-core-7.0.57.jar!/:7.0.57]
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:611) ~[tomcat-embed-core-7.0.57.jar!/:7.0.57]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1736) ~[tomcat-embed-core-7.0.57.jar!/:7.0.57]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1695) ~[tomcat-embed-core-7.0.57.jar!/:7.0.57]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1146) ~[na:1.6.0_33]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) ~[na:1.6.0_33]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-7.0.57.jar!/:7.0.57]
    at java.lang.Thread.run(Thread.java:701) ~[na:1.6.0_33]
Daniel Zolnai
  • 16,487
  • 7
  • 59
  • 71
Marek
  • 1,413
  • 2
  • 20
  • 36

1 Answers1

32

The simplest way to configure a DataSource in Spring Boot is to create an application.properties file under src/main/resources with the following content (may need to update it with correct url, username and password):

spring.datasource.url=jdbc:mysql://localhost/:3306/databasename
spring.datasource.username=root
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

Spring Boot will automatically create the DataSource class for you and inject it to other beans. As a result of that, you won't need the xml config file anymore and may get rid of this line in the Application class:

@ImportResource("classpath:spring/application-config.xml")

Also, in the UserDAOImpl Spring can autowire the JdbcTemplate object using the DataSource bean (http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-sql.html#boot-features-using-jdbc-template) so you don't need to create one each time the insert() method is called.

As for the init() method in UserDAOImpl, you could create a schema.sql file under src/main/resources and move the CREATE TABLE statement there (for more details see http://docs.spring.io/spring-boot/docs/1.2.0.RELEASE/reference/htmlsingle/#howto-intialize-a-database-using-spring-jdbc)

See this example for more information: http://xantorohara.blogspot.ca/2013/11/spring-boot-jdbc-sample.html

kaviddiss
  • 594
  • 4
  • 9
  • Thank you kaviddiss for you answer. I just created application.properties file under src/main/resources and unfortunately I keep having same error message. I also tryed to put it under src/main/resources/spring directory and it gave the same result. Are you sure it must be com.mysql.jdbc.Driver as driver package? – Marek Dec 30 '14 at 13:59
  • What's the error message you are getting? The driver class name is specific to the DB you're using. If it's mysql, the value should be com.mysql.jdbc.Driver in the properties file. – kaviddiss Dec 30 '14 at 14:36
  • It is mysql, in that case driver is correct. The stack message is too long to post it in the comment, so I edited the question adding it at the end. Thanks again! – Marek Dec 30 '14 at 17:32
  • Can you try changing DriverManagerDataSource to DataSource in the setDataSource() method in UserDAOImpl? – kaviddiss Dec 30 '14 at 19:14
  • Yes of course, I replaced it by DataSource from javax.sql.DataSource and unfortunately I get same error. – Marek Dec 30 '14 at 19:25
  • In TestWS you need to autowire users as a field, otherwise the data source will not be injected: @Autowired private UserDAO users; – kaviddiss Dec 30 '14 at 19:45
  • unfortunately I cannot autowire UserDAOImpl (neither UserDAO) because those are not beans, following error: `No qualifying bean of type [dao.UserDAOImpl] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency.` – Marek Dec 30 '14 at 20:08
  • 3
    Please check these links for help: http://xantorohara.blogspot.ca/2013/11/spring-boot-jdbc-sample.html and http://blog.netgloo.com/2014/10/27/using-mysql-in-spring-boot-via-spring-data-jpa-and-hibernate/ – kaviddiss Dec 30 '14 at 21:52
  • Sorry I took time to implement the example, unfortunately I cannot use the first one since it uses Gradle and my project is Maven bases, however I transformed my code to fit the second example (took some time to fix dependencies) and I keep having same error `Could not autowire field: private dao.UserDAO ws.TestWS._userDAO;...` At the beginning I supposed it the fault of main class, but after accessing the github repository I noticed it is also exactly the same... – Marek Dec 31 '14 at 12:25
  • I finally managed to make it work. Thank you very much for the example you gave me. I will accept your answer if you will add the link you mentioned (because this was actually the solution). Please add this link `xantorohara.blogspot.ca/2013/11/spring-boot-jdbc-sample.html` and I will accept your answer as solution :). Thank you again and cheers! – Marek Jan 04 '15 at 12:09
  • You helped me too :) Thanks! – Georgi Stoyanov Dec 29 '15 at 09:36