From b33eb95dd2ba22b814c84af374bb4cd25490b813 Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Thu, 8 May 2014 15:54:31 +0200 Subject: [PATCH] Added DriverClassNameProvider used for providing jdbc driver class based on jdbc url Uses known databases from org.flywaydb.core.internal.util.jdbc.DriverDataSource Fixes gh-824, fixes gh-809 --- .../jdbc/DataSourceProperties.java | 21 ++++- .../jdbc/DriverClassNameProvider.java | 79 +++++++++++++++++++ .../DataSourceAutoConfigurationTests.java | 5 ++ .../jdbc/DataSourcePropertiesTests.java | 31 ++++++++ .../jdbc/DriverClassNameProviderTest.java | 54 +++++++++++++ 5 files changed, 187 insertions(+), 3 deletions(-) create mode 100644 spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DriverClassNameProvider.java create mode 100644 spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourcePropertiesTests.java create mode 100644 spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DriverClassNameProviderTest.java diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceProperties.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceProperties.java index 59b398737dc..830f751b60e 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceProperties.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceProperties.java @@ -20,12 +20,15 @@ import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.InitializingBean; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; /** * Base class for configuration of a database pool. * * @author Dave Syer + * @author Maciej Walkowiak * @since 1.1.0 */ @ConfigurationProperties(prefix = DataSourceAutoConfiguration.CONFIGURATION_PREFIX) @@ -53,6 +56,8 @@ public class DataSourceProperties implements BeanClassLoaderAware, InitializingB private EmbeddedDatabaseConnection embeddedDatabaseConnection = EmbeddedDatabaseConnection.NONE; + private DriverClassNameProvider driverClassNameProvider = new DriverClassNameProvider(); + @Override public void setBeanClassLoader(ClassLoader classLoader) { this.classLoader = classLoader; @@ -64,11 +69,22 @@ public class DataSourceProperties implements BeanClassLoaderAware, InitializingB .get(this.classLoader); } - public String getDriverClassName() { + protected String getDriverClassName() { if (StringUtils.hasText(this.driverClassName)) { + Assert.state(ClassUtils.isPresent(this.driverClassName, null), + "Cannot load driver class: " + this.driverClassName); return this.driverClassName; } - String driverClassName = this.embeddedDatabaseConnection.getDriverClassName(); + String driverClassName = null; + + if (StringUtils.hasText(this.url)) { + driverClassName = this.driverClassNameProvider.getDriverClassName(this.url); + } + + if (!StringUtils.hasText(driverClassName)) { + driverClassName = this.embeddedDatabaseConnection.getDriverClassName(); + } + if (!StringUtils.hasText(driverClassName)) { throw new BeanCreationException( "Cannot determine embedded database driver class for database type " @@ -173,5 +189,4 @@ public class DataSourceProperties implements BeanClassLoaderAware, InitializingB public ClassLoader getClassLoader() { return this.classLoader; } - } diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DriverClassNameProvider.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DriverClassNameProvider.java new file mode 100644 index 00000000000..32f013a5db2 --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DriverClassNameProvider.java @@ -0,0 +1,79 @@ +/* + * Copyright 2012-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.boot.autoconfigure.jdbc; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.util.Assert; + +/** + * Provides JDBC driver class name for given JDBC URL. + * + * @author Maciej Walkowiak + * @since 1.1.0 + */ +class DriverClassNameProvider { + + private static final String JDBC_URL_PREFIX = "jdbc"; + + private static final Map driverMap = new HashMap() { + { + put("db2", "com.ibm.db2.jcc.DB2Driver"); + put("derby", "org.apache.derby.jdbc.EmbeddedDriver"); + put("h2", "org.h2.Driver"); + put("hsqldb", "org.hsqldb.jdbcDriver"); + put("sqlite", "org.sqlite.JDBC"); + put("mysql", "com.mysql.jdbc.Driver"); + put("mariadb", "org.mariadb.jdbc.Driver"); + put("google", "com.google.appengine.api.rdbms.AppEngineDriver"); + put("oracle", "oracle.jdbc.OracleDriver"); + put("postgresql", "org.postgresql.Driver"); + put("jtds", "net.sourceforge.jtds.jdbc.Driver"); + put("sqlserver", "com.microsoft.sqlserver.jdbc.SQLServerDriver"); + + } + }; + + /** + * Used to find JDBC driver class name based on given JDBC URL + * + * @param jdbcUrl JDBC URL + * @return driver class name or null if not found + */ + String getDriverClassName(final String jdbcUrl) { + Assert.notNull(jdbcUrl, "JDBC URL cannot be null"); + + if (!jdbcUrl.startsWith(JDBC_URL_PREFIX)) { + throw new IllegalArgumentException("JDBC URL should start with '" + + JDBC_URL_PREFIX + "'"); + } + + String urlWithoutPrefix = jdbcUrl.substring(JDBC_URL_PREFIX.length()); + String result = null; + + for (Map.Entry driver : driverMap.entrySet()) { + if (urlWithoutPrefix.startsWith(":" + driver.getKey() + ":")) { + result = driver.getValue(); + + break; + } + } + + return result; + } + +} diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfigurationTests.java index 108d80d43dc..f252e6b9f25 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfigurationTests.java @@ -95,6 +95,8 @@ public class DataSourceAutoConfigurationTests { @Test(expected = BeanCreationException.class) public void testBadUrl() throws Exception { + EnvironmentTestUtils.addEnvironment(this.context, + "spring.datasource.url:jdbc:not-going-to-work"); EmbeddedDatabaseConnection.override = EmbeddedDatabaseConnection.NONE; this.context.register(DataSourceAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class); @@ -104,6 +106,9 @@ public class DataSourceAutoConfigurationTests { @Test(expected = BeanCreationException.class) public void testBadDriverClass() throws Exception { + EnvironmentTestUtils.addEnvironment(this.context, + "spring.datasource.driverClassName:org.none.jdbcDriver", + "spring.datasource.url:jdbc:hsqldb:mem:testdb"); EmbeddedDatabaseConnection.override = EmbeddedDatabaseConnection.NONE; this.context.register(DataSourceAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class); diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourcePropertiesTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourcePropertiesTests.java new file mode 100644 index 00000000000..e2c9781634b --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourcePropertiesTests.java @@ -0,0 +1,31 @@ +package org.springframework.boot.autoconfigure.jdbc; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Tests for {@link DataSourceProperties}. + * + * @author Maciej Walkowiak + */ +public class DataSourcePropertiesTests { + + @Test + public void correctDriverClassNameFromJdbcUrlWhenDriverClassNameNotDefined() { + DataSourceProperties configuration = new DataSourceProperties(); + configuration.setUrl("jdbc:mysql://mydb"); + String driverClassName = configuration.getDriverClassName(); + assertEquals(driverClassName, "com.mysql.jdbc.Driver"); + } + + @Test + public void driverClassNameFromDriverClassNamePropertyWhenDefined() { + DataSourceProperties configuration = new DataSourceProperties(); + configuration.setUrl("jdbc:mysql://mydb"); + configuration.setDriverClassName("my.driver.ClassName"); + String driverClassName = configuration.getDriverClassName(); + assertEquals(driverClassName, "my.driver.ClassName"); + } + +} diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DriverClassNameProviderTest.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DriverClassNameProviderTest.java new file mode 100644 index 00000000000..b7494b8b291 --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DriverClassNameProviderTest.java @@ -0,0 +1,54 @@ +/* + * Copyright 2012-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.boot.autoconfigure.jdbc; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +/** + * Tests for {@link DriverClassNameProvider}. + * + * @author Maciej Walkowiak + */ +public class DriverClassNameProviderTest { + private DriverClassNameProvider driverClassNameProvider = new DriverClassNameProvider(); + + @Test + public void testGettingClassNameForKnownDatabase() { + String driverClassName = driverClassNameProvider.getDriverClassName("jdbc:postgresql://hostname/dbname"); + + assertEquals("org.postgresql.Driver", driverClassName); + } + + @Test + public void testReturnsNullForUnknownDatabase() { + String driverClassName = driverClassNameProvider.getDriverClassName("jdbc:unknowndb://hostname/dbname"); + + assertNull(driverClassName); + } + + @Test(expected = IllegalArgumentException.class) + public void testFailureOnNullJdbcUrl() { + driverClassNameProvider.getDriverClassName(null); + } + + @Test(expected = IllegalArgumentException.class) + public void testFailureOnMalformedJdbcUrl() { + driverClassNameProvider.getDriverClassName("malformed:url"); + } +} \ No newline at end of file