java.lang.IllegalArgumentException: jdbcUrl is required with driverClassName error occurs when Hikari could not locate the database url while creating a datasource using database credentials. When Spring Boot tries to create multiple datasources to connect multiple databases in a single application, this error java.lang.IllegalArgumentException: jdbcUrl is required with driverClassName occurs. Hikari is used to create datasources for which the database url could not be found using the database credentials.
The Hikari jdbc driver class was unable to locate the jdbc url required to create a datasource to connect to a database. Hikari searches for different property name in the application properties to read the jdbc url in the driver loaded from the name specified as in the driver class name. The jdbc url property in the application.properties should be updated as per the Hikari driver class. Alternatively the datasource bean should be manually created in spring boot.
Exception
The stack trace of the exception java.lang.IllegalArgumentException: jdbcUrl is required with driverClassName is shown as below. The mismatch of the url configured in application.properties and expected jdbc url in the Hikari database driver will cause this error.
2021-08-26 18:28:48.975[0;39m [31mERROR[0;39m [35m64146[0;39m [2m---[0;39m [2m[ main][0;39m [36mcom.zaxxer.hikari.HikariConfig [0;39m [2m:[0;39m HikariPool-1 - jdbcUrl is required with driverClassName.
[2m2021-08-26 18:28:48.977[0;39m [33m WARN[0;39m [35m64146[0;39m [2m---[0;39m [2m[ main][0;39m [36mo.h.e.j.e.i.JdbcEnvironmentInitiator [0;39m [2m:[0;39m HHH000342: Could not obtain connection to query metadata
java.lang.IllegalArgumentException: jdbcUrl is required with driverClassName.
at com.zaxxer.hikari.HikariConfig.validate(HikariConfig.java:1025) ~[HikariCP-4.0.3.jar:na]
at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:109) ~[HikariCP-4.0.3.jar:na]
at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:122) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess.obtainConnection(JdbcEnvironmentInitiator.java:180) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:68) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:35) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.initiateService(StandardServiceRegistryImpl.java:101) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:263) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:237) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:214) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.id.factory.internal.DefaultIdentifierGeneratorFactory.injectServices(DefaultIdentifierGeneratorFactory.java:152) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
Root Cause
The database jdbc driver could not create a datasource to connect the database if the database url property key specified in the application.properties file and the anticipated property key in the database Hikari jdbc driver are different. When a spring boot application tries to create multiple datasources to connect multiple databases, this error “java.lang.IllegalArgumentException: jdbcUrl is required with driverClassName” is common. The error will be addressed if the configuration mismatch is corrected.
Solution 1
The configuration mismatch can be resolved by correcting the property name according to the Hikari database driver. The spring boot database url “spring.datasource.url” should be changed to “spring.datasource.jdbc-url”.
spring.datasource.url=jdbc:mysql://localhost/testdb
to
spring.datasource.jdbc-url=jdbc:mysql://localhost/testdb
application.properties
spring.datasource.url=jdbc:mysql://localhost/testdb
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.database=default
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
Solution 2
The “java.lang.IllegalArgumentException: jdbcUrl is required with driverClassName” error occurs when spring boot application tries to create multiple datasource to connect multiple datasource. The datasource can be created using the database properties as specified in the below code.
PrimaryDBConfig.java
package com.yawintutor;
import javax.persistence.EntityManagerFactory;
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.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import com.zaxxer.hikari.HikariDataSource;
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "primaryEntityManagerFactory",
transactionManagerRef = "primaryTransactionManager",
basePackages = { "com.yawintutor.primary" }
)
public class PrimaryDBConfig {
@Bean
@Primary
@ConfigurationProperties("spring.datasource")
public DataSourceProperties dataSourceProperties() {
return new DataSourceProperties();
}
@Bean(name="primaryDataSource")
@Primary
@ConfigurationProperties(prefix="spring.datasource")
public HikariDataSource primaryDataSource(DataSourceProperties properties) {
return properties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
}
@Primary
@Bean(name = "primaryEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean primaryEntityManagerFactory(EntityManagerFactoryBuilder builder,
@Qualifier("primaryDataSource") DataSource primaryDataSource) {
return builder
.dataSource(primaryDataSource)
.packages("com.yawintutor.primary")
.build();
}
@Bean(name = "primaryTransactionManager")
public PlatformTransactionManager primaryTransactionManager(
@Qualifier("primaryEntityManagerFactory") EntityManagerFactory primaryEntityManagerFactory) {
return new JpaTransactionManager(primaryEntityManagerFactory);
}
}
Solution 3
The datasource can be created by reading the properties from the application.properties using environment. The datasource will be created manually with all the properties are assigned in the datasource.
package com.yawintutor;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "primaryEntityManagerFactory",
transactionManagerRef = "primaryTransactionManager",
basePackages = { "com.yawintutor.primary" }
)
public class PrimaryDBConfig {
@Autowired
Environment env;
@Bean(name="primaryDataSource")
@Primary
@ConfigurationProperties(prefix="spring.datasource")
public DataSource primaryDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl(env.getProperty("spring.datasource.url"));
dataSource.setUsername(env.getProperty("spring.datasource.username"));
dataSource.setPassword(env.getProperty("spring.datasource.password"));
dataSource.setDriverClassName(env.getProperty("spring.datasource.driver-class-name"));
return dataSource;
}
@Primary
@Bean(name = "primaryEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean primaryEntityManagerFactory(EntityManagerFactoryBuilder builder,
@Qualifier("primaryDataSource") DataSource primaryDataSource) {
return builder
.dataSource(primaryDataSource)
.packages("com.yawintutor.primary")
.build();
}
@Bean(name = "primaryTransactionManager")
public PlatformTransactionManager primaryTransactionManager(
@Qualifier("primaryEntityManagerFactory") EntityManagerFactory primaryEntityManagerFactory) {
return new JpaTransactionManager(primaryEntityManagerFactory);
}
}