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 f060ed5dd13d..c94f25503d28 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 @@ void whenNoInitializationRelatedSpringDataSourcePropertiesAreConfiguredThenIniti 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 a678929a1ac1..6e6dc962101d 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 e096662f16c4..067caffe7ef6 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 1b679a0ab54f..9c2284d402bf 100644 --- a/spring-boot-project/spring-boot/build.gradle +++ b/spring-boot-project/spring-boot/build.gradle @@ -28,6 +28,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 b8c0f8d3aeef..62d85ccc0549 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 javax.sql.DataSource; +import com.mchange.v2.c3p0.ComboPooledDataSource; import com.zaxxer.hikari.HikariDataSource; import oracle.jdbc.datasource.OracleDataSource; import oracle.ucp.jdbc.PoolDataSource; @@ -391,6 +393,8 @@ private static MappedDataSourceProperties lookupPooled 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; } @@ -650,6 +654,29 @@ public Class getDataSourceInstanceType() { } + /** + * {@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 345c58e1aead..c80ff388af75 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 @@ -26,6 +26,7 @@ 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; @@ -384,6 +385,19 @@ void buildWhenDerivedFromCustomTypeWithTypeChange() { 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"); + } + final class HidePackagesClassLoader extends URLClassLoader { private final String[] hiddenPackages;