From 5f7657508fc90beb8153b7bc061d02cfebe4545c Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 4 Feb 2022 11:27:29 +0100 Subject: [PATCH 1/3] Start building against Spring Batch 4.3.5 snapshots See gh-29652 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 3a57db1e82b..da203b42c25 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -1646,7 +1646,7 @@ bom { ] } } - library("Spring Batch", "4.3.4") { + library("Spring Batch", "4.3.5-SNAPSHOT") { group("org.springframework.batch") { modules = [ "spring-batch-core", From 8c8c9c5f28baef63dad6bdd8a4ebe3baa58e6ded Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 4 Feb 2022 10:14:36 +0100 Subject: [PATCH 2/3] Upgrade to H2 2.1.210 H2 2.x contains several important changes such as moving the primary key generation mechanism to a sequence-based identifier. This commit fixes a number of tests that were failing. Closes gh-29651 Co-authored-by: Andy Wilkinson --- .../flyway/Flyway5xAutoConfigurationTests.java | 12 +++++++----- .../flyway/Flyway6xAutoConfigurationTests.java | 12 +++++++----- .../flyway/Flyway7xAutoConfigurationTests.java | 10 ++++++---- .../jpa/HibernateJpaAutoConfigurationTests.java | 2 +- .../orm/jpa/mapping/NonAnnotatedEntity.java | 16 ++++++++-------- .../META-INF/mappings/non-annotated.xml | 4 ++-- .../src/test/resources/db/non-annotated-data.sql | 2 +- .../spring-boot-dependencies/build.gradle | 2 +- .../orm/jpa/DataJpaTestIntegrationTests.java | 5 ++--- .../main/java/smoketest/test/domain/User.java | 4 +++- .../src/test/resources/data.sql | 2 +- 11 files changed, 39 insertions(+), 32 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/Flyway5xAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/Flyway5xAutoConfigurationTests.java index 4dbff8c68c1..d2fc87842a2 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/Flyway5xAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/Flyway5xAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-2022 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. @@ -16,6 +16,8 @@ package org.springframework.boot.autoconfigure.flyway; +import java.util.UUID; + import org.flywaydb.core.Flyway; import org.flywaydb.core.api.Location; import org.flywaydb.core.api.MigrationVersion; @@ -23,7 +25,7 @@ import org.flywaydb.core.api.migration.JavaMigration; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.testsupport.classpath.ClassPathOverrides; import org.springframework.context.annotation.Bean; @@ -41,11 +43,11 @@ class Flyway5xAutoConfigurationTests { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(FlywayAutoConfiguration.class)) - .withPropertyValues("spring.datasource.generate-unique-name=true"); + .withPropertyValues("spring.datasource.url:jdbc:hsqldb:mem:" + UUID.randomUUID()); @Test void defaultFlyway() { - this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class).run((context) -> { + this.contextRunner.withUserConfiguration(DataSourceAutoConfiguration.class).run((context) -> { assertThat(context).hasSingleBean(Flyway.class); Flyway flyway = context.getBean(Flyway.class); assertThat(flyway.getConfiguration().getLocations()) @@ -56,7 +58,7 @@ class Flyway5xAutoConfigurationTests { @Test void flywayJavaMigrationsAreIgnored() { this.contextRunner - .withUserConfiguration(EmbeddedDataSourceConfiguration.class, FlywayJavaMigrationsConfiguration.class) + .withUserConfiguration(DataSourceAutoConfiguration.class, FlywayJavaMigrationsConfiguration.class) .run((context) -> assertThat(context).hasNotFailed()); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/Flyway6xAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/Flyway6xAutoConfigurationTests.java index fd169165fd8..bb5faa2e85d 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/Flyway6xAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/Flyway6xAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2022 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. @@ -16,6 +16,8 @@ package org.springframework.boot.autoconfigure.flyway; +import java.util.UUID; + import org.flywaydb.core.Flyway; import org.flywaydb.core.api.Location; import org.flywaydb.core.api.callback.Callback; @@ -25,7 +27,7 @@ import org.junit.jupiter.api.Test; import org.mockito.InOrder; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.testsupport.classpath.ClassPathOverrides; import org.springframework.context.annotation.Bean; @@ -48,11 +50,11 @@ class Flyway6xAutoConfigurationTests { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(FlywayAutoConfiguration.class)) - .withPropertyValues("spring.datasource.generate-unique-name=true"); + .withPropertyValues("spring.datasource.url:jdbc:hsqldb:mem:" + UUID.randomUUID()); @Test void defaultFlyway() { - this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class).run((context) -> { + this.contextRunner.withUserConfiguration(DataSourceAutoConfiguration.class).run((context) -> { assertThat(context).hasSingleBean(Flyway.class); Flyway flyway = context.getBean(Flyway.class); assertThat(flyway.getConfiguration().getLocations()) @@ -62,7 +64,7 @@ class Flyway6xAutoConfigurationTests { @Test void callbacksAreConfiguredAndOrdered() { - this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class, CallbackConfiguration.class) + this.contextRunner.withUserConfiguration(DataSourceAutoConfiguration.class, CallbackConfiguration.class) .run((context) -> { assertThat(context).hasSingleBean(Flyway.class); Flyway flyway = context.getBean(Flyway.class); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/Flyway7xAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/Flyway7xAutoConfigurationTests.java index f37c7fb6a97..777b7e38a62 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/Flyway7xAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/Flyway7xAutoConfigurationTests.java @@ -16,6 +16,8 @@ package org.springframework.boot.autoconfigure.flyway; +import java.util.UUID; + import org.flywaydb.core.Flyway; import org.flywaydb.core.api.Location; import org.flywaydb.core.api.callback.Callback; @@ -24,7 +26,7 @@ import org.flywaydb.core.api.callback.Event; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.testsupport.classpath.ClassPathOverrides; import org.springframework.context.annotation.Bean; @@ -47,11 +49,11 @@ class Flyway7xAutoConfigurationTests { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(FlywayAutoConfiguration.class)) - .withPropertyValues("spring.datasource.generate-unique-name=true"); + .withPropertyValues("spring.datasource.url:jdbc:hsqldb:mem:" + UUID.randomUUID()); @Test void defaultFlyway() { - this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class).run((context) -> { + this.contextRunner.withUserConfiguration(DataSourceAutoConfiguration.class).run((context) -> { assertThat(context).hasSingleBean(Flyway.class); Flyway flyway = context.getBean(Flyway.class); assertThat(flyway.getConfiguration().getLocations()) @@ -61,7 +63,7 @@ class Flyway7xAutoConfigurationTests { @Test void callbacksAreConfigured() { - this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class, CallbackConfiguration.class) + this.contextRunner.withUserConfiguration(DataSourceAutoConfiguration.class, CallbackConfiguration.class) .run((context) -> { assertThat(context).hasSingleBean(Flyway.class); Flyway flyway = context.getBean(Flyway.class); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java index b526445c783..6b271f10bd3 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java @@ -318,7 +318,7 @@ class HibernateJpaAutoConfigurationTests extends AbstractJpaAutoConfigurationTes EntityManager em = context.getBean(EntityManagerFactory.class).createEntityManager(); NonAnnotatedEntity found = em.find(NonAnnotatedEntity.class, 2000L); assertThat(found).isNotNull(); - assertThat(found.getValue()).isEqualTo("Test"); + assertThat(found.getItem()).isEqualTo("Test"); }); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/mapping/NonAnnotatedEntity.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/mapping/NonAnnotatedEntity.java index 7ed418d43c2..b9f41c89358 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/mapping/NonAnnotatedEntity.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/mapping/NonAnnotatedEntity.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2022 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. @@ -25,13 +25,13 @@ public class NonAnnotatedEntity { private Long id; - private String value; + private String item; protected NonAnnotatedEntity() { } - public NonAnnotatedEntity(String value) { - this.value = value; + public NonAnnotatedEntity(String item) { + this.item = item; } public Long getId() { @@ -42,12 +42,12 @@ public class NonAnnotatedEntity { this.id = id; } - public String getValue() { - return this.value; + public String getItem() { + return this.item; } - public void setValue(String value) { - this.value = value; + public void setItem(String value) { + this.item = value; } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/resources/META-INF/mappings/non-annotated.xml b/spring-boot-project/spring-boot-autoconfigure/src/test/resources/META-INF/mappings/non-annotated.xml index db6bee33194..3b33b0dff38 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/resources/META-INF/mappings/non-annotated.xml +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/resources/META-INF/mappings/non-annotated.xml @@ -10,8 +10,8 @@ - - + + diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/resources/db/non-annotated-data.sql b/spring-boot-project/spring-boot-autoconfigure/src/test/resources/db/non-annotated-data.sql index 709bc377bcc..b741d23ccf8 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/resources/db/non-annotated-data.sql +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/resources/db/non-annotated-data.sql @@ -1 +1 @@ -INSERT INTO NON_ANNOTATED (ID, VALUE) values (2000, 'Test'); +INSERT INTO NON_ANNOTATED (id, item) values (2000, 'Test'); diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index da203b42c25..8499fd22c82 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -399,7 +399,7 @@ bom { ] } } - library("H2", "1.4.200") { + library("H2", "2.1.210") { group("com.h2database") { modules = [ "h2" diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestIntegrationTests.java index 723dd514edd..3f1d9e26319 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2022 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. @@ -27,7 +27,6 @@ import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfigurati import org.springframework.context.ApplicationContext; import org.springframework.data.repository.config.BootstrapMode; import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.test.context.TestPropertySource; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; @@ -41,7 +40,6 @@ import static org.springframework.boot.test.autoconfigure.AutoConfigurationImpor * @author Scott Frederick */ @DataJpaTest -@TestPropertySource(properties = "spring.jpa.hibernate.use-new-id-generator-mappings=false") class DataJpaTestIntegrationTests { @Autowired @@ -71,6 +69,7 @@ class DataJpaTestIntegrationTests { @Test void testEntityManagerPersistAndGetId() { Long id = this.entities.persistAndGetId(new ExampleEntity("spring", "123"), Long.class); + this.entities.flush(); assertThat(id).isNotNull(); String reference = this.jdbcTemplate.queryForObject("SELECT REFERENCE FROM EXAMPLE_ENTITY WHERE ID = ?", String.class, id); diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-test/src/main/java/smoketest/test/domain/User.java b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-test/src/main/java/smoketest/test/domain/User.java index 05fef4cc700..c81eee54678 100644 --- a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-test/src/main/java/smoketest/test/domain/User.java +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-test/src/main/java/smoketest/test/domain/User.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2022 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. @@ -20,6 +20,7 @@ import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; +import javax.persistence.Table; import org.springframework.util.Assert; @@ -29,6 +30,7 @@ import org.springframework.util.Assert; * @author Phillip Webb */ @Entity +@Table(name = "DRIVER") public class User { @Id diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-test/src/test/resources/data.sql b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-test/src/test/resources/data.sql index 70ecc99a379..7ea61039b1f 100644 --- a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-test/src/test/resources/data.sql +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-test/src/test/resources/data.sql @@ -1 +1 @@ -INSERT INTO USER(ID, USERNAME, VIN) values (123, 'sframework', '01234567890123456'); +INSERT INTO DRIVER(id, username, vin) values (123, 'sframework', '01234567890123456'); From 098a57affb40a4bb2f43724b0e69ff9948376716 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 2 Feb 2022 09:47:10 +0100 Subject: [PATCH 3/3] Upgrade to R2DBC Borca-RELEASE See gh-28524 --- .../r2dbc/R2dbcAutoConfigurationTests.java | 14 ++++--- .../spring-boot-dependencies/build.gradle | 2 +- .../spring-boot-docs/build.gradle | 2 +- .../boot/r2dbc/ConnectionFactoryBuilder.java | 42 ++++++++++++------- .../r2dbc/ConnectionFactoryBuilderTests.java | 31 +++++++++++--- .../build.gradle | 2 +- .../build.gradle | 2 +- 7 files changed, 65 insertions(+), 30 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/r2dbc/R2dbcAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/r2dbc/R2dbcAutoConfigurationTests.java index 3c7d9ac491b..2f4f7d3093d 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/r2dbc/R2dbcAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/r2dbc/R2dbcAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-2022 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. @@ -93,7 +93,7 @@ class R2dbcAutoConfigurationTests { assertThat(context).hasSingleBean(ConnectionFactory.class).hasSingleBean(ConnectionPool.class) .hasSingleBean(R2dbcProperties.class); ConnectionPool connectionPool = context.getBean(ConnectionPool.class); - assertThat(connectionPool).hasFieldOrPropertyWithValue("maxAcquireTime", Duration.ZERO); + assertThat(connectionPool).hasFieldOrPropertyWithValue("maxAcquireTime", Duration.ofNanos(-1)); }); } @@ -156,8 +156,9 @@ class R2dbcAutoConfigurationTests { assertThat(context).hasSingleBean(ConnectionFactory.class).doesNotHaveBean(ConnectionPool.class); ConnectionFactory connectionFactory = context.getBean(ConnectionFactory.class); assertThat(connectionFactory).asInstanceOf(type(OptionsCapableConnectionFactory.class)) - .extracting(OptionsCapableConnectionFactory::getOptions).satisfies((options) -> assertThat( - options.getRequiredValue(Option.valueOf("customized"))).isTrue()); + .extracting(OptionsCapableConnectionFactory::getOptions) + .satisfies((options) -> assertThat(options.getRequiredValue(Option.valueOf("customized"))) + .isEqualTo(Boolean.TRUE)); }); } @@ -169,8 +170,9 @@ class R2dbcAutoConfigurationTests { ConnectionFactory pool = context.getBean(ConnectionFactory.class); ConnectionFactory connectionFactory = ((ConnectionPool) pool).unwrap(); assertThat(connectionFactory).asInstanceOf(type(OptionsCapableConnectionFactory.class)) - .extracting(OptionsCapableConnectionFactory::getOptions).satisfies((options) -> assertThat( - options.getRequiredValue(Option.valueOf("customized"))).isTrue()); + .extracting(OptionsCapableConnectionFactory::getOptions) + .satisfies((options) -> assertThat(options.getRequiredValue(Option.valueOf("customized"))) + .isEqualTo(Boolean.TRUE)); }); } diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 8499fd22c82..1c428f674c1 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -1389,7 +1389,7 @@ bom { ] } } - library("R2DBC Bom", "Arabba-SR12") { + library("R2DBC Bom", "Borca-RELEASE") { group("io.r2dbc") { imports = [ "r2dbc-bom" diff --git a/spring-boot-project/spring-boot-docs/build.gradle b/spring-boot-project/spring-boot-docs/build.gradle index 2a23cb83014..e5691af8c58 100644 --- a/spring-boot-project/spring-boot-docs/build.gradle +++ b/spring-boot-project/spring-boot-docs/build.gradle @@ -80,7 +80,6 @@ dependencies { implementation("io.micrometer:micrometer-registry-graphite") implementation("io.micrometer:micrometer-registry-jmx") implementation("io.projectreactor.netty:reactor-netty-http") - implementation("io.r2dbc:r2dbc-postgresql") implementation("io.undertow:undertow-core") implementation("jakarta.annotation:jakarta.annotation-api") implementation("jakarta.jms:jakarta.jms-api") @@ -114,6 +113,7 @@ dependencies { } implementation("org.mockito:mockito-core") implementation("org.mongodb:mongodb-driver-sync") + implementation("org.postgresql:r2dbc-postgresql") implementation("org.quartz-scheduler:quartz") implementation("org.slf4j:jul-to-slf4j") implementation("org.springframework:spring-jdbc") diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/r2dbc/ConnectionFactoryBuilder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/r2dbc/ConnectionFactoryBuilder.java index 1125d53d3b0..04d583391a8 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/r2dbc/ConnectionFactoryBuilder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/r2dbc/ConnectionFactoryBuilder.java @@ -24,11 +24,13 @@ import java.util.function.Function; import io.r2dbc.pool.ConnectionPool; import io.r2dbc.pool.ConnectionPoolConfiguration; import io.r2dbc.pool.PoolingConnectionFactoryProvider; +import io.r2dbc.spi.Connection; import io.r2dbc.spi.ConnectionFactories; import io.r2dbc.spi.ConnectionFactory; import io.r2dbc.spi.ConnectionFactoryOptions; import io.r2dbc.spi.ConnectionFactoryOptions.Builder; import io.r2dbc.spi.ValidationDepth; +import org.reactivestreams.Publisher; import org.springframework.boot.context.properties.PropertyMapper; import org.springframework.util.Assert; @@ -209,7 +211,7 @@ public final class ConnectionFactoryBuilder { } private ConnectionFactoryOptions delegateFactoryOptions(ConnectionFactoryOptions options) { - String protocol = options.getRequiredValue(ConnectionFactoryOptions.PROTOCOL); + String protocol = toString(options.getRequiredValue(ConnectionFactoryOptions.PROTOCOL)); if (protocol.trim().length() == 0) { throw new IllegalArgumentException(String.format("Protocol %s is not valid.", protocol)); } @@ -221,35 +223,45 @@ public final class ConnectionFactoryBuilder { .option(ConnectionFactoryOptions.PROTOCOL, protocolDelegate).build(); } + @SuppressWarnings("unchecked") ConnectionPoolConfiguration connectionPoolConfiguration(ConnectionFactoryOptions options, ConnectionFactory connectionFactory) { ConnectionPoolConfiguration.Builder builder = ConnectionPoolConfiguration.builder(connectionFactory); PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); - map.from((Object) options.getValue(PoolingConnectionFactoryProvider.BACKGROUND_EVICTION_INTERVAL)) + map.from(options.getValue(PoolingConnectionFactoryProvider.BACKGROUND_EVICTION_INTERVAL)) .as(this::toDuration).to(builder::backgroundEvictionInterval); - map.from((Object) options.getValue(PoolingConnectionFactoryProvider.INITIAL_SIZE)).as(this::toInteger) + map.from(options.getValue(PoolingConnectionFactoryProvider.INITIAL_SIZE)).as(this::toInteger) .to(builder::initialSize); - map.from((Object) options.getValue(PoolingConnectionFactoryProvider.MAX_SIZE)).as(this::toInteger) + map.from(options.getValue(PoolingConnectionFactoryProvider.MAX_SIZE)).as(this::toInteger) .to(builder::maxSize); - map.from((Object) options.getValue(PoolingConnectionFactoryProvider.ACQUIRE_RETRY)).as(this::toInteger) + map.from(options.getValue(PoolingConnectionFactoryProvider.ACQUIRE_RETRY)).as(this::toInteger) .to(builder::acquireRetry); - map.from((Object) options.getValue(PoolingConnectionFactoryProvider.MAX_LIFE_TIME)).as(this::toDuration) + map.from(options.getValue(PoolingConnectionFactoryProvider.MAX_LIFE_TIME)).as(this::toDuration) .to(builder::maxLifeTime); - map.from((Object) options.getValue(PoolingConnectionFactoryProvider.MAX_ACQUIRE_TIME)).as(this::toDuration) + map.from(options.getValue(PoolingConnectionFactoryProvider.MAX_ACQUIRE_TIME)).as(this::toDuration) .to(builder::maxAcquireTime); - map.from((Object) options.getValue(PoolingConnectionFactoryProvider.MAX_IDLE_TIME)).as(this::toDuration) + map.from(options.getValue(PoolingConnectionFactoryProvider.MAX_IDLE_TIME)).as(this::toDuration) .to(builder::maxIdleTime); - map.from((Object) options.getValue(PoolingConnectionFactoryProvider.MAX_CREATE_CONNECTION_TIME)) - .as(this::toDuration).to(builder::maxCreateConnectionTime); - map.from(options.getValue(PoolingConnectionFactoryProvider.POOL_NAME)).to(builder::name); - map.from((Object) options.getValue(PoolingConnectionFactoryProvider.REGISTER_JMX)).as(this::toBoolean) + map.from(options.getValue(PoolingConnectionFactoryProvider.MAX_CREATE_CONNECTION_TIME)).as(this::toDuration) + .to(builder::maxCreateConnectionTime); + map.from(options.getValue(PoolingConnectionFactoryProvider.POOL_NAME)).as(this::toString).to(builder::name); + map.from(options.getValue(PoolingConnectionFactoryProvider.PRE_RELEASE)).to((function) -> builder + .preRelease((Function>) function)); + map.from(options.getValue(PoolingConnectionFactoryProvider.POST_ALLOCATE)).to((function) -> builder + .postAllocate((Function>) function)); + map.from(options.getValue(PoolingConnectionFactoryProvider.REGISTER_JMX)).as(this::toBoolean) .to(builder::registerJmx); - map.from(options.getValue(PoolingConnectionFactoryProvider.VALIDATION_QUERY)).to(builder::validationQuery); - map.from((Object) options.getValue(PoolingConnectionFactoryProvider.VALIDATION_DEPTH)) - .as(this::toValidationDepth).to(builder::validationDepth); + map.from(options.getValue(PoolingConnectionFactoryProvider.VALIDATION_QUERY)).as(this::toString) + .to(builder::validationQuery); + map.from(options.getValue(PoolingConnectionFactoryProvider.VALIDATION_DEPTH)).as(this::toValidationDepth) + .to(builder::validationDepth); return builder.build(); } + private String toString(Object object) { + return toType(String.class, object, String::valueOf); + } + private Integer toInteger(Object object) { return toType(Integer.class, object, Integer::valueOf); } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/r2dbc/ConnectionFactoryBuilderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/r2dbc/ConnectionFactoryBuilderTests.java index 443d9c80ea4..3b4896666da 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/r2dbc/ConnectionFactoryBuilderTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/r2dbc/ConnectionFactoryBuilderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-2022 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. @@ -20,6 +20,7 @@ import java.time.Duration; import java.util.ArrayList; import java.util.List; import java.util.UUID; +import java.util.function.Function; import io.r2dbc.h2.H2ConnectionFactoryMetadata; import io.r2dbc.pool.ConnectionPool; @@ -35,7 +36,9 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import org.springframework.boot.r2dbc.ConnectionFactoryBuilder.PoolingAwareOptionsCapableWrapper; +import org.springframework.core.ResolvableType; import org.springframework.util.ReflectionUtils; +import org.springframework.util.ReflectionUtils.FieldFilter; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; @@ -198,9 +201,13 @@ class ConnectionFactoryBuilderTests { assertThat(configuration).extracting(expectedOption.property).isEqualTo(expectedOption.value); } + private static Iterable poolingConnectionProviderOptions() { + return extractPoolingConnectionProviderOptions((field) -> Option.class.equals(field.getType())); + } + @ParameterizedTest @SuppressWarnings({ "rawtypes", "unchecked" }) - @MethodSource("poolingConnectionProviderOptions") + @MethodSource("primitivePoolingConnectionProviderOptions") void stringlyTypedOptionIsMappedWhenCreatingPoolConfiguration(Option option) { String url = "r2dbc:pool:h2:mem:///" + UUID.randomUUID(); ExpectedOption expectedOption = ExpectedOption.get(option); @@ -213,11 +220,21 @@ class ConnectionFactoryBuilderTests { assertThat(configuration).extracting(expectedOption.property).isEqualTo(expectedOption.value); } - private static Iterable poolingConnectionProviderOptions() { + private static Iterable primitivePoolingConnectionProviderOptions() { + return extractPoolingConnectionProviderOptions((field) -> { + ResolvableType type = ResolvableType.forField(field); + if (!type.toClass().equals(Option.class)) { + return false; + } + Class valueType = type.as(Option.class).getGenerics()[0].toClass(); + return valueType.getPackage().getName().equals("java.lang"); + }); + } + + private static Iterable extractPoolingConnectionProviderOptions(FieldFilter filter) { List arguments = new ArrayList<>(); ReflectionUtils.doWithFields(PoolingConnectionFactoryProvider.class, - (field) -> arguments.add(Arguments.of(ReflectionUtils.getField(field, null))), - (field) -> Option.class.equals(field.getType())); + (field) -> arguments.add(Arguments.of(ReflectionUtils.getField(field, null))), filter); return arguments; } @@ -250,6 +267,10 @@ class ConnectionFactoryBuilderTests { POOL_NAME(PoolingConnectionFactoryProvider.POOL_NAME, "testPool", "name"), + POST_ALLOCATE(PoolingConnectionFactoryProvider.POST_ALLOCATE, mock(Function.class), "postAllocate"), + + PRE_RELEASE(PoolingConnectionFactoryProvider.PRE_RELEASE, mock(Function.class), "preRelease"), + REGISTER_JMX(PoolingConnectionFactoryProvider.REGISTER_JMX, true, "registerJmx"), VALIDATION_QUERY(PoolingConnectionFactoryProvider.VALIDATION_QUERY, "SELECT 1", "validationQuery"), diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-r2dbc-flyway/build.gradle b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-r2dbc-flyway/build.gradle index 3f4a53ce7c7..32ac145609a 100644 --- a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-r2dbc-flyway/build.gradle +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-r2dbc-flyway/build.gradle @@ -8,9 +8,9 @@ description = "Spring Boot Data R2DBC with Flyway smoke test" dependencies { implementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-data-r2dbc")) - runtimeOnly("io.r2dbc:r2dbc-postgresql") runtimeOnly("org.flywaydb:flyway-core") runtimeOnly("org.postgresql:postgresql") + runtimeOnly("org.postgresql:r2dbc-postgresql") runtimeOnly("org.springframework:spring-jdbc") testImplementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-test")) diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-r2dbc-liquibase/build.gradle b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-r2dbc-liquibase/build.gradle index c37dac862e2..19fb9b574c5 100644 --- a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-r2dbc-liquibase/build.gradle +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-r2dbc-liquibase/build.gradle @@ -8,12 +8,12 @@ description = "Spring Boot Data R2DBC with Liquibase smoke test" dependencies { implementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-data-r2dbc")) - runtimeOnly("io.r2dbc:r2dbc-postgresql") runtimeOnly("org.liquibase:liquibase-core") { exclude group: "javax.activation", module: "javax.activation-api" exclude group: "javax.xml.bind", module: "jaxb-api" } runtimeOnly("org.postgresql:postgresql") + runtimeOnly("org.postgresql:r2dbc-postgresql") runtimeOnly("org.springframework:spring-jdbc") testImplementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-test"))