Auto configurations are one of the best features at spring boot. Spring boot supports auto-configured datasource. The credentials for the database are included in application.properties. Spring boot builds a datasource object dynamically from the configurations. If an error occurs in the initialization phase of the datasource, the error will be thrown.
Normaly, any time this issue has happened, there are two errors seen together. The two errors are shown in the stack trace of exception below. If the configurations are not available, this error will be thrown at the application startup by spring boot.
2020-02-29 08:26:34.599 WARN 47009 --- [ main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'springBootSecurityConfiguration': Unsatisfied dependency expressed through field 'dataSource'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'javax.sql.DataSource' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
2020-02-29 08:26:34.602 INFO 47009 --- [ main] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
2020-02-29 08:26:34.612 INFO 47009 --- [ main] ConditionEvaluationReportLoggingListener :
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2020-02-29 08:26:34.680 ERROR 47009 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter :
***************************
APPLICATION FAILED TO START
***************************
Description:
Field dataSource in com.yawintutor.SpringBootSecurityConfiguration required a bean of type 'javax.sql.DataSource' that could not be found.
The injection point has the following annotations:
- @org.springframework.beans.factory.annotation.Autowired(required=true)
The following candidates were found but could not be injected:
- Bean method 'dataSource' in 'JndiDataSourceAutoConfiguration' not loaded because @ConditionalOnProperty (spring.datasource.jndi-name) did not find property 'jndi-name'
- Bean method 'dataSource' in 'XADataSourceAutoConfiguration' not loaded because @ConditionalOnClass did not find required class 'javax.transaction.TransactionManager'
Action:
Consider revisiting the entries above or defining a bean of type 'javax.sql.DataSource' in your configuration.
Root Cause
Spring boot uses the configurations to create database connections. The datasource is a JPA entity, responsible for maintaining the credentials of the database. That helps to create connections to the database.
If in the spring boot application the spring boot JPA module is attached, the datasource is not enabled, then this error occurs.
How to reproduce this issue
Build an application for spring boot with spring boot security module, spring jpa modules and database. This error will occur if the data base details are not configured in the urls of the datasource.
Solution 1
Check the pom.xml file. The “spring-boot-starter-data-jpa” modules and the database should be configured. If this isn’t available, add the dependency modules. For this case it is using the h2 database. So this pom.xml file is connected with the module “com.h2database.”
If you are using a database such as mysql, sqlserver, oracle etc, add the dependency for the respective database in the pom.xml file. The complete pom.xml file is shown as below.
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.4.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.yawintutor</groupId>
<artifactId>Spring-Application</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>SpringBootSecurityDatabase</name>
<description>Spring Boot Project</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Solution 2
Check the file application.properties. The url of the data source must be configured in the application.properties. Spring boot Check the “spring.datasource.url” property to make connections to the database. Make sure that this property is configured correctly in the spring boot application.
application.properties
spring.datasource.url=jdbc:h2:file:./DB
spring.jpa.properties.hibernate.hbm2ddl.auto=update
Solution 3
Check the custom code, how to build the object Datasource. In some modules, such as spring boot security, it requires adding the datasource to the code. When you skip the datasource then this exception is thrown away. Make sure that the data source object is auto-wired within the spring boot application
SpringBootSecurityConfiguration.java
package com.yawintutor;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
public class SpringBootSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private DataSource dataSource;
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication()
.dataSource(dataSource)
.withDefaultSchema()
.withUser("user")
.password("{noop}password").roles("USER");
}
@Override
public void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/dashboard").hasAnyRole("USER")
.and().formLogin().loginPage("/login").defaultSuccessUrl("/dashboard")
.permitAll()
.and().logout();
}
}