Spring/tomcat Cannot load driver class: com.mysql.jdbc.driver - spring

Lately I have been trying to learn spring boot. I have the following relevant files:
an #Configuration class: I use this to generate the entitymanagerfactory
an #Entity class: I use this to map to a mysql table instance
an #Repository crudrepository interface: this is built in to spring
an #Controller class: this is used to test auto-wiring (when I can inject, I will move this to the service layer)
an #SpringBootApplication class: this runs my application
an application.properties file
a pom.xml: this is used for maven and includes mysql jar
an entity class mapped to a mysql table and a UserRepository class(annotated with #Repository). I am trying to inject the crudrepository class via #Autowire annotation, but spring is having difficulty creating the datasource for it because it cannot find the mysql driver. What confuses me is that I have the mysql dependency in maven and I am deploying this on a glassfish 4 server, but Spring is trying to use apache tomcat to connect to the database. Below is my stack trace, code snippets, and mysql-connector:
Relevant Stack Trace (inner exception)
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.apache.tomcat.jdbc.pool.DataSource]: Factory method 'dataSource' threw exception; nested exception is java.lang.IllegalStateException: Cannot load driver class: com.mysql.jdbc.driver
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
... 62 common frames omitted
Caused by: java.lang.IllegalStateException: Cannot load driver class: com.mysql.jdbc.driver
notice how this is trying to use org.apache.tomcat to create datasource, even though I am using a glassfish server. Does this matter?
Source Code: the first relevant exception occurs when spring tries to inject the datasource bean that is a parameter to this method and can't create it
#Configuration
#EnableAutoConfiguration
public class AppConfigUtil {
#Autowired
#Bean
public EntityManagerFactory entityManagerFactory(DataSource dataSource) {
LocalContainerEntityManagerFactoryBean bean = new LocalContainerEntityManagerFactoryBean();
bean.setPackagesToScan("com.connor");
bean.setDataSource(dataSource);
return bean.getObject();
}
Maven (pom.xml) for mysql jar:
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
application.properties: this is the entirety of my application.properties file spring uses to generate datasource
spring.datasource.url=jdbc:mysql://localhost:3307/craigslist
spring.datasource.username=dbadmin
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.jdbc.driver
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.show_sql=true
hibernate.format_sql=true
Here is picture of my maven dependencies: the mysql jar is present:
downloaded maven dependencies: including mysql jar
Any ideas on how to fix this?

Assuming you are using Spring boot.
Here are some things you can do to make it work (You might have done some of these, I added anything I can think of just to make sure):
Remove your AppConfigUtil class because Spring boot will "magically" find the datasource for you if your application.properties is configured right.
Add #SpringBootApplication to your ConnerApplication.java class
Add spring-boot-starter-data-jpa dependency in your pom
Some side notes:
#Autowire is not intended to be marked with #Bean annotation. #Autowire CAN be used to autowire bean which is annotated with #Bean.
EDIT :
I realized that OP wants to deploy it on Glassfish. In that case, you will need to tweak Spring to produce a deployable war file and configure your application container (glassfish) to include a jdbc driver. All of it is doable but requires a lot of efforts.
I suggested that you go with embedded tomcat approach if you use Spring-boot for new project. It is basically battle-ready. You can hardly go wrong with this.

You don't need declare in pom.xml
spring.datasource.driver-class-name=com.mysql.jdbc.driver
You can read my configuration in a simple app using Spring Boot here
Beside, if you're using Spring Boot you don't need use codes "Source Code: the first relevant exception occurs when spring tries to inject the datasource bean that is a parameter to this method and can't create it..."

Related

#EnableAutoConfiguration(exclude =...) on tests failed in Spring Boot 2.6.0

I tried to upgrade my data-mongo example project to Spring Boot 2.6.0. There is a test designed to run against Testcontainers, I also included the embedded mongo dep for other tests, so I have to exclude the AutoConfiguration for embedded mongo to make sure this test working on Docker/testcontainers.
The following configuration worked well with Spring Boot 2.5.6.
#DataMongoTest
#ContextConfiguration(initializers = {MongodbContainerInitializer.class})
#EnableAutoConfiguration(exclude = EmbeddedMongoAutoConfiguration.class)
#Slf4j
#ActiveProfiles("test")
public class PostRepositoryTest {}
But after upgrading to Spring Boot 2.6.0 and running the application, I got the exception like this.
[ main] s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: o
rg.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'embeddedMongoServer' defined in class path resource [org/springframework/boot/autoconfig
ure/mongo/embedded/EmbeddedMongoAutoConfiguration.class]: Unsatisfied dependency expressed through method 'embeddedMongoServer' parameter 0; nested exception is org.springframework.bea
ns.factory.BeanCreationException: Error creating bean with name 'embeddedMongoConfiguration' defined in class path resource [org/springframework/boot/autoconfigure/mongo/embedded/Embed
dedMongoAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [de.flap
doodle.embed.mongo.config.MongodConfig]: Factory method 'embeddedMongoConfiguration' threw exception; nested exception is java.lang.IllegalStateException: Set the spring.mongodb.embedd
ed.version property or define your own MongodConfig bean to use embedded MongoDB
Obviously, #EnableAutoConfiguration(exclude =...) did not affect the context in tests when upgrading to Spring Boot 2.6.0.
Update: Temporarily resolved it, see my answer below.
Just add:
#TestPropertySource(properties = "spring.mongodb.embedded.version=3.5.5")
annotation before your Unit Test and it will start working.
#Henning's answer has a good explanation of why you need this.
As of Spring Boot 2.6, the property spring.mongodb.embedded.version must be set to use the auto-configured embedded MongoDB. It's mentioned in the release notes: https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.6-Release-Notes#embedded-mongo
This is also what the error message you posted, advises to do: Set the spring.mongodb.embedd ed.version property or define your own MongodConfig bean to use embedded MongoDB
The annotation #DataMongoTest is meta-annotated with #ImportAutoConfiguration and #AutoConfigureDataMongo, and is designed to trigger auto-configuration of MongoDB unless explicitly disabled as you do in the working configuration examples.
In your first configuration example, the annotation #EnableAutoConfiguration(exclude = EmbeddedMongoAutoConfiguration.class) does not override this effect of #DataMongoTest.
With Spring Boot 2.5.6, the auto-configured MongodConfig bean is most likely also part of the application context but not effectively used. But this depends on the rest of the code and in particular on the MongodbContainerInitializer.
Use #ImportAutoConfiguration(exclude = ...) or #DataMongoTest(excludeAutoConfiguration = ...) on test classes to overcome this barrier when upgrading to Spring Boot 2.6.0.
#DataMongoTest
#ImportAutoConfiguration(exclude = EmbeddedMongoAutoConfiguration.class)
//other config are ommitted
public class PostRepositoryTest {}
//or
#DataMongoTest(excludeAutoConfiguration = EmbeddedMongoAutoConfiguration.class)
public class PostRepositoryTest {}

Spring Boot external DataSource bean

I am trying to create a common library that includes several stuff needed by my microservices. One of those things is the ACL functionality provided with spring-security. My initial thought was to initialize all ACL-related beans from a #Configuration file in the common library and each time a microservice needs this functionality i could use the #Import annotation(to my microservice project) to "enable" it.
Some of these beans require the famous javax.sql.DataSource to work, so in my common library i autowired it as follows:
#Configuration
public class AclConfiguration {
#Autowired
DataSource dataSource
When i decide that i want this configuration to take place i go to my microservice project (let's say RulesApplication) and on the main class (annotated with #SpringBootApplication) i do the following
#SpringBootApplication
#EnableJpaRepositories
#EnableJpaAuditing
#EnableCaching
#Import(AclConfiguration.class)
public class RulesApplication {
.
.
.
The problem is that the DataSource bean cannot be seen from the common library, although it is being created as expected (validated just by removing the #Import).
Everytime i import the configuration from the common library i get a :
Caused by: java.lang.IllegalArgumentException: DataSource required
at org.springframework.util.Assert.notNull(Assert.java:198) ~[spring-core-5.2.5.RELEASE.jar:5.2.5.RELEASE]
Indicating that the DataSource bean is null.
What am i missing here?
Coming up from some digging.. There was never a real problem with the DataSource bean. All the frustration was created by double-defining another Bean in the same class, which led to all the #Autowired beans failure to initialize.
As a result from this research(as other posts mentioned) the bean initialization is working smoothly between shared projects, so most of the times this error will occur from double-defining/badly-defining other beans.

Spring Boot connect to Postgres database on Heroku

I've been playing around with a Spring Boot app deployed on Heroku but I've stumbled upon an error that I can't seem to find a solution.
I'm trying to connect to a Postgres database following the Heroku tutorial (link) but I get this error over and over again:
Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException:
Failed to instantiate [javax.sql.DataSource]:
Factory method 'dataSource' threw exception; nested exception is java.lang.IllegalStateException: No supported DataSource type found
Here's the config file I'm using:
spring.datasource.url=${JDBC_DATABASE_URL}
spring.datasource.driverClassName=org.postgresql.Driver
spring.datasource.username=username
spring.datasource.password=password
spring.datasource.removeAbandoned=true
And the DatabaseConfig class:
#Configuration
public class DatabaseConfig {
#Bean #Primary
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create()
.build();
}
}
Can anyone point me in the right direction. What am I doing wrong?
I encountered this same exact issue and managed to solve it. The issue is not specific to Heroku, because it can be reproduced by running the app locally as well using the same configuration.
According to the stacktrace it is clear that a DataSource has not been found in the class path. According to Spring Boot documentation, found here, you can either use spring-boot-starter-jdbc or spring-boot-starter-data-jpa to automatically get tomcat-jdbc, which appears to be the preferred one in Spring Boot.
I added the following dependency to pom.xml, which solved the problem:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

SpringBoot Datasource AutoConfiguration Not Working

I have a simple SpringBoot application and I'd like to use AutoConfiguration to configure the Tomcat jdbc pooled data sources.
I am using these Spring dependencies:
// Spring Boot
compile 'org.springframework.boot:spring-boot-starter-web:1.3.5.RELEASE'
compile 'org.springframework.boot:spring-boot-starter-jdbc:1.3.5.RELEASE'
Here are my datasource properties in my application.yml file:
spring:
datasource:
url: jdbc:mysql://my.host/mydb
username: user
password: pwd
driver-class-name: com.mysql.jdbc.Driver
initialSize: 5
I am sure the properties are being loaded because the app is picking up other values.
I define the bean in my config file as:
#Bean(name="myDataSource")
#ConfigurationProperties(prefix="spring.datasource")
public DataSource getDataSource() {
DataSource dataSource = DataSourceBuilder.create().build()
return dataSource
}
And I inject the datasource into my DAO like this:
#Slf4j
#Repository
class MyDAO {
#Autowired
DataSource dataSource
public void getFoo() {
log.info("DB URL: ${dataSource.getUrl()}")
}
}
If I set a breakpoint in the getDataSource() method, the DataSourceBuilder will create an instance of DataSource. However, all the properties of that object like URL, user and password are all null. Also, when I call getFoo(), the dataSource variable is null. I have tried commenting out the bean definition in my AppConfig. The dataSource is still null. Any suggestions?
I looked through the Spring Boot documentation and my Spring book but I didn't see any examples like this. I see examples where I create the DataSource myself. But I was hoping Spring's auto-configuration would tie this stuff together automatically.
Thanks in advance for any help you can provide.
By creating your own bean, you're actually switching off Boot's auto-configuration of a DataSource. You can just delete your getDataSource method and let Boot auto-configure one instead.
Based on Andy's comments I found out that I had two problems. First of all, I needed to include the JPA dependency to the project. I added this line to my build.gradle file:
compile 'org.springframework.boot:spring-boot-starter-data-jpa:1.3.5.RELEASE'
Second, I was creating instances of MyDAO using new(). I fixed this by creating a service class that used #Autowired to inject an instance of MyDAO. Once the DAO became a Spring managed bean, it was able to inject the instance of DataSource from the Tomcat connection pool.

Spring Boot with multiple datasources and in memory database

I'm trying to set up Spring Boot to work with multiple datasources. I have followed the instructions for setting up two datasources and set one of them primary.
#Configuration
#EnableJpaRepositories(basePackages={"my.postgres.repositories"}
entityManagerFactoryRef="postgresEntitymanager"
transactionManagerRef="postgresTransactionManager")
public class PgConfig {
#Primary
#Bean(name="postgresDS")
#ConfigurationProperties(prefix="spring.datasource.postgres")
public DataSource postgresDataSource() {
return DataSourceBuilder.create().build();
}
#Primary
#Bean(name="postgresEntityManager")
public LocalContainerEntityManagerFactoryBean postgresEntityManager(EntityManagerFactoryBuilder builder) {
return builder.dataSource(postgresDataSource())
.packages("my.postgres.domain")
.persistenceUnit("postgresPersistenceUnit")
.build();
}
#Primary
#Bean(name = "postgresTransactionManager")
public PlatformTransactionManager postgresTransactionManager(
#Qualifier("postgresEntityManager") EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
I have a second configuration class for oracle which lacks the #Primary annotation but is very similar. I have also added this to my main class to exclude datasource auto configuration.
#SpringBootApplication(exclude={DataSourceAutoConfiguration.class})
The problem that I'm facing is this setup doesn't allow my Integration tests that are supposed to run against an H2 databse to open a connection...
Caused by: javax.persistence.PersistenceException: org.hibernate.exception.JDBCConnectionException: Could not open connection
Caused by: javax.persistence.PersistenceException: org.hibernate.exception.JDBCConnectionException: Could not open connection
Caused by: org.hibernate.exception.JDBCConnectionException: Could not open connection
Caused by: java.sql.SQLException: The url cannot be null
I'm using a separate application.properties file under src/integrationtest/resources which contains
spring.jpa.database=H2
How do I get my integration tests to use H2 for the repositories that I'm using when running my tests?
If I don't include my custom datasources everything seems to work fine.
Thanks
You can add your own test's configuration with h2 database but use other database in production. You've excluded DataSourceAutoConfiguration in your spring application class, but it's usefull in your integration tests.
One simple solution is using a different spring application class only for your integrating tests without excluding DataSourceAutoConfiguration or just implement your own DataSourceAutoConfiguration and enable it. You can decide when will your own DataSourceAutoConfiguration be enabled or not within your own implementation. For example, if there are junit or spring-test exists in your classpath it will be enabled, otherwise will be disabled. This requires the junit or spring-test not going to be included in production, which can be handled by dependencies management such as maven.

Resources