diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfigurationTests.java index f060ed5dd1..c94f25503d 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfigurationTests.java @@ -240,7 +240,7 @@ class DataSourceAutoConfigurationTests { private static Function hideConnectionPools() { return (runner) -> runner.withClassLoader(new FilteredClassLoader("org.apache.tomcat", "com.zaxxer.hikari", - "org.apache.commons.dbcp2", "oracle.ucp.jdbc")); + "org.apache.commons.dbcp2", "oracle.ucp.jdbc", "com.mchange")); } private void assertDataSource(Class expectedType, List hiddenPackages, diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/data/sql.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/data/sql.adoc index a678929a1a..6e6dc96210 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/data/sql.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/data/sql.adoc @@ -135,6 +135,7 @@ The following connection pools are supported by `DataSourceBuilder`: * Spring Framework's `SimpleDriverDataSource` * H2 `JdbcDataSource` * PostgreSQL `PGSimpleDataSource` +* C3P0 diff --git a/spring-boot-project/spring-boot-parent/build.gradle b/spring-boot-project/spring-boot-parent/build.gradle index 40955f6f4a..d9f7854429 100644 --- a/spring-boot-project/spring-boot-parent/build.gradle +++ b/spring-boot-project/spring-boot-parent/build.gradle @@ -27,6 +27,13 @@ bom { ] } } + library("C3P0", "0.9.5.5") { + group("com.mchange") { + modules = [ + "c3p0" + ] + } + } library("Commons Compress", "1.21") { group("org.apache.commons") { modules = [ diff --git a/spring-boot-project/spring-boot/build.gradle b/spring-boot-project/spring-boot/build.gradle index a1184748eb..4a12ee8b40 100644 --- a/spring-boot-project/spring-boot/build.gradle +++ b/spring-boot-project/spring-boot/build.gradle @@ -25,6 +25,7 @@ dependencies { optional("com.fasterxml.jackson.core:jackson-databind") optional("com.h2database:h2") optional("com.google.code.gson:gson") + optional("com.mchange:c3p0") optional("com.oracle.database.jdbc:ucp") optional("com.oracle.database.jdbc:ojdbc8") optional("com.samskivert:jmustache") diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/DataSourceBuilder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/DataSourceBuilder.java index 291a051fc3..e57712d378 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/DataSourceBuilder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/DataSourceBuilder.java @@ -16,6 +16,7 @@ package org.springframework.boot.jdbc; +import java.beans.PropertyVetoException; import java.lang.reflect.Method; import java.sql.SQLException; import java.util.Collections; @@ -27,6 +28,7 @@ import java.util.function.Supplier; import javax.sql.DataSource; +import com.mchange.v2.c3p0.ComboPooledDataSource; import com.zaxxer.hikari.HikariDataSource; import oracle.jdbc.datasource.OracleDataSource; import oracle.ucp.jdbc.PoolDataSource; @@ -419,6 +421,8 @@ public final class DataSourceBuilder { MappedDbcp2DataSource::new); result = lookup(classLoader, type, result, "oracle.ucp.jdbc.PoolDataSourceImpl", OraclePoolDataSourceProperties::new, "oracle.jdbc.OracleConnection"); + result = lookup(classLoader, type, result, "com.mchange.v2.c3p0.ComboPooledDataSource", + ComboPooledDataSourceProperties::new); return result; } @@ -678,6 +682,29 @@ public final class DataSourceBuilder { } + /** + * {@link DataSourceProperties} for C3P0. + */ + private static class ComboPooledDataSourceProperties extends MappedDataSourceProperties { + + ComboPooledDataSourceProperties() { + add(DataSourceProperty.URL, ComboPooledDataSource::getJdbcUrl, ComboPooledDataSource::setJdbcUrl); + add(DataSourceProperty.DRIVER_CLASS_NAME, ComboPooledDataSource::getDriverClass, this::setDriverClass); + add(DataSourceProperty.USERNAME, ComboPooledDataSource::getUser, ComboPooledDataSource::setUser); + add(DataSourceProperty.PASSWORD, ComboPooledDataSource::getPassword, ComboPooledDataSource::setPassword); + } + + private void setDriverClass(ComboPooledDataSource dataSource, String driverClass) { + try { + dataSource.setDriverClass(driverClass); + } + catch (PropertyVetoException ex) { + throw new IllegalArgumentException(ex); + } + } + + } + /** * {@link DataSourceProperties} for Spring's {@link SimpleDriverDataSource}. */ diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/DataSourceBuilderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/DataSourceBuilderTests.java index 283028291c..ad2852adfc 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/DataSourceBuilderTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/DataSourceBuilderTests.java @@ -29,6 +29,7 @@ import java.util.logging.Logger; import javax.sql.DataSource; +import com.mchange.v2.c3p0.ComboPooledDataSource; import com.microsoft.sqlserver.jdbc.SQLServerDataSource; import com.zaxxer.hikari.HikariDataSource; import oracle.jdbc.internal.OpaqueString; @@ -400,6 +401,19 @@ class DataSourceBuilderTests { assertThat(testSource.getPassword()).isEqualTo("secret"); } + @Test // gh-31920 + void buildWhenC3P0TypeSpecifiedReturnsExpectedDataSource() { + this.dataSource = DataSourceBuilder.create().url("jdbc:postgresql://localhost:5432/postgres") + .type(ComboPooledDataSource.class).username("test").password("secret") + .driverClassName("com.example.Driver").build(); + assertThat(this.dataSource).isInstanceOf(ComboPooledDataSource.class); + ComboPooledDataSource c3p0DataSource = (ComboPooledDataSource) this.dataSource; + assertThat(c3p0DataSource.getJdbcUrl()).isEqualTo("jdbc:postgresql://localhost:5432/postgres"); + assertThat(c3p0DataSource.getUser()).isEqualTo("test"); + assertThat(c3p0DataSource.getPassword()).isEqualTo("secret"); + assertThat(c3p0DataSource.getDriverClass()).isEqualTo("com.example.Driver"); + } + private DataSource wrap(DataSource target) { return new DataSourceWrapper(target); }