Reputation: 1119
I am trying to add an external jar at runtime and then use that jar to connect to a database (instead of having to add many drivers to the pom, the goal is to provide the user the ability to load any driver jar at runtime). I am using a spring boot project and I am trying to use spring boots DataSourceBuilder to create the datasource.
The answers and suggestions in Loading JDBC Driver at Runtime and Loading jars at runtime do not seem to work for the following code:
@Component
public class DriverLoader {
private static final String URL = "jdbc:mysql://localhost:3306/sakila?useSSL=false";
private static final String USER = "root";
private static final String ADMIN = "admin";
private static final String DRIVER_JAR = "C:\\Users\\Sander\\Downloads\\mysql-connector-java-5.1.40.jar";
@PostConstruct
private void loadDriver() throws Exception {
File file = new File(DRIVER_JAR);
if (file != null) {
URLClassLoader URLClassLoader = new URLClassLoader(new URL[] {file.toURI().toURL()}, System.class.getClassLoader());
String driverName = DatabaseDriver.fromJdbcUrl(URL).getDriverClassName();
System.out.println(driverName);
// lets try to load the class
Class<?> driverClass = URLClassLoader.loadClass(driverName);
Driver actualDriver = (Driver) driverClass.newInstance();
URLClassLoader.close();
// Throws: Caused by: java.lang.ClassNotFoundException: com.mysql.jdbc.StringUtils
/*Properties properties = new Properties();
properties.put("user", USER);
properties.put("password", ADMIN);
Connection con = actualDriver.connect(URL, properties);*/
DataSource dataSource = createNewDataSource(URL, USER, ADMIN);
if (dataSource != null) {
// lets try to connect
// Throws: Caused by: java.lang.ClassNotFoundException: com.mysql.jdbc.Driver
dataSource.getConnection().isValid(1);
}
}
}
public DataSource createNewDataSource(String url, String username, String password) {
return DataSourceBuilder
.create()
.url(url)
.username(username)
.password(password)
.build();
}
}
Snippet of the pom I am using:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
How can I use the DataSourceBuilder to succesfully establish a connection with a datasource given that the jar file has been added at runtime?
Full stack trace:
2017-02-04 20:13:22.201 ERROR 12528 --- [ main] o.a.tomcat.jdbc.pool.ConnectionPool : Unable to create initial connections of pool.
java.sql.SQLException: Unable to load class: com.mysql.jdbc.Driver from ClassLoader:sun.misc.Launcher$AppClassLoader@764c12b6;ClassLoader:sun.misc.Launcher$AppClassLoader@764c12b6
at org.apache.tomcat.jdbc.pool.PooledConnection.connectUsingDriver(PooledConnection.java:283) ~[tomcat-jdbc-8.5.11.jar:na]
at org.apache.tomcat.jdbc.pool.PooledConnection.connect(PooledConnection.java:203) ~[tomcat-jdbc-8.5.11.jar:na]
at org.apache.tomcat.jdbc.pool.ConnectionPool.createConnection(ConnectionPool.java:732) [tomcat-jdbc-8.5.11.jar:na]
at org.apache.tomcat.jdbc.pool.ConnectionPool.borrowConnection(ConnectionPool.java:664) [tomcat-jdbc-8.5.11.jar:na]
at org.apache.tomcat.jdbc.pool.ConnectionPool.init(ConnectionPool.java:479) [tomcat-jdbc-8.5.11.jar:na]
at org.apache.tomcat.jdbc.pool.ConnectionPool.<init>(ConnectionPool.java:154) [tomcat-jdbc-8.5.11.jar:na]
at org.apache.tomcat.jdbc.pool.DataSourceProxy.pCreatePool(DataSourceProxy.java:118) [tomcat-jdbc-8.5.11.jar:na]
at org.apache.tomcat.jdbc.pool.DataSourceProxy.createPool(DataSourceProxy.java:107) [tomcat-jdbc-8.5.11.jar:na]
at org.apache.tomcat.jdbc.pool.DataSourceProxy.getConnection(DataSourceProxy.java:131) [tomcat-jdbc-8.5.11.jar:na]
at nl.mierasmade.driver.DriverLoader.loadDriver(DriverLoader.java:54) [classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_112]
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_112]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_112]
at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_112]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:366) [spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:311) [spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:134) [spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:409) [spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1620) [spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) [spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) [spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) [spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) [spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) [spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) [spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761) [spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:866) [spring-context-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:542) [spring-context-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:737) [spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:370) [spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:314) [spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1162) [spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1151) [spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
at nl.mierasmade.JdbcRuntimeDriverApplication.main(JdbcRuntimeDriverApplication.java:10) [classes/:na]
Caused by: java.lang.ClassNotFoundException: Unable to load class: com.mysql.jdbc.Driver from ClassLoader:sun.misc.Launcher$AppClassLoader@764c12b6;ClassLoader:sun.misc.Launcher$AppClassLoader@764c12b6
at org.apache.tomcat.jdbc.pool.ClassLoaderUtil.loadClass(ClassLoaderUtil.java:56) ~[tomcat-jdbc-8.5.11.jar:na]
at org.apache.tomcat.jdbc.pool.PooledConnection.connectUsingDriver(PooledConnection.java:271) ~[tomcat-jdbc-8.5.11.jar:na]
... 33 common frames omitted
Caused by: java.lang.ClassNotFoundException: com.mysql.jdbc.Driver
at java.net.URLClassLoader.findClass(Unknown Source) ~[na:1.8.0_112]
at java.lang.ClassLoader.loadClass(Unknown Source) ~[na:1.8.0_112]
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source) ~[na:1.8.0_112]
at java.lang.ClassLoader.loadClass(Unknown Source) ~[na:1.8.0_112]
at java.lang.Class.forName0(Native Method) ~[na:1.8.0_112]
at java.lang.Class.forName(Unknown Source) ~[na:1.8.0_112]
at org.apache.tomcat.jdbc.pool.ClassLoaderUtil.loadClass(ClassLoaderUtil.java:38) ~[tomcat-jdbc-8.5.11.jar:na]
... 34 common frames omitted
Upvotes: 2
Views: 2220
Reputation: 51431
I was able to get to work like this:
@Bean
public DataSource dynamicDataSource() {
ClassLoader classLoader = new URLClassLoader(new URL[]{new URL("file:///C:/Users/xxxx/Desktop/h2-1.4.193.jar")}, Thread.currentThread().getContextClassLoader());
Thread.currentThread().setContextClassLoader(classLoader);
DataSource dataSource = DataSourceBuilder.create().url('jdbc:h2:mem:test;DB_CLOSE_DELAY=-1').build();
dataSource.getConnection().isValid(10);
return dataSource;
}
Upvotes: 2