spring-projects / spring-projects/spring-boot
@ServiceConnection on a PostgreSQL container produces JdbcConnectionDetails but not R2dbcConnectionDetails
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 81.5k
- Forks
- 42.7k
- Avg merge
- 2d 4h
- Merged PRs (30d)
- 65
Description
@ServiceConnection on a PostgreSQLContainer produces JdbcConnectionDetails but not R2dbcConnectionDetails
Spring Boot version: 4.0.0
Testcontainers version: reproduced on both 2.0.4 and 1.21.2
Java: 25 · Kotlin: 2.4.10 · Build: Gradle, io.spring.dependency-management
Docker: 28.3.2 (macOS, aarch64)
Summary
A PostgreSQLContainer @Bean annotated @ServiceConnection in a @TestConfiguration supplies connection
details to Flyway (JDBC) but not to R2DBC. Flyway connects to the container and migrates successfully, proving
JdbcConnectionDetails is published. In the same context, the application's ConnectionFactory ignores the
container and uses whatever spring.r2dbc.url resolves to, which means R2dbcConnectionDetails is absent.
Because the fallback is a working property rather than an error, this fails as an obscure connection error to
whatever host the property names, rather than as a missing-bean or misconfiguration message.
Reproduction
@TestConfiguration(proxyBeanMethods = false)
class ContainerConfiguration {
@Bean
@ServiceConnection
fun postgres(): PostgreSQLContainer = PostgreSQLContainer("postgres:17")
}
@SpringBootApplication
@Import(ContainerConfiguration::class)
class TestApplication
@SpringBootTest(classes = [TestApplication::class])
@ActiveProfiles("test")
class SomeIntegrationTest { /* autowires a repository backed by R2DBC */ }
application-test.yaml:
spring:
r2dbc:
url: r2dbc:postgresql://ignored.invalid:5432/ignored # deliberately unreachable
pool:
enabled: true
Expected: the container's R2dbcConnectionDetails takes precedence and the application connects to the
container, as it does for Flyway over JDBC.
Actual:
org.springframework.dao.DataAccessResourceFailureException: Failed to obtain R2DBC Connection
Caused by: io.r2dbc.postgresql.PostgresqlConnectionFactory$PostgresConnectionException:
[08003] Cannot connect to ignored.invalid/<unresolved>:5432
Caused by: java.net.UnknownHostException: ignored.invalid
The container is running and healthy throughout.
Evidence that R2dbcConnectionDetails is genuinely absent
R2dbcAutoConfiguration.propertiesR2dbcConnectionDetails is annotated
@ConditionalOnMissingBean(R2dbcConnectionDetails.class). The properties-backed implementation is therefore
created only when no other R2dbcConnectionDetails bean exists. Since the application demonstrably uses the
property value, the container's bean is not present.
Cross-check: removing spring.r2dbc.url from the test profile and giving the placeholder in the main
application.yaml an unreachable default made the application connect to that default instead — again showing
the property is being consulted rather than overridden.
Flyway, in the same context and from the same container bean, connects correctly and migrates the full schema.
So @ServiceConnection processing is working; only the R2DBC side produces nothing.
What was ruled out
Each of these was changed independently and the behaviour did not change:
| variable | values tried |
|---|---|
| Testcontainers version | 2.0.4 (org.testcontainers.postgresql.PostgreSQLContainer) and 1.21.2 (org.testcontainers.containers.PostgreSQLContainer) |
| container image | custom image built via ImageFromDockerfile + asCompatibleSubstituteFor("postgres"), and stock postgres:17 |
| where the configuration is imported | @Import on the @SpringBootApplication class named in @SpringBootTest(classes = …), and @Import directly on the test class |
| connection name | default, and explicit @ServiceConnection("postgresql") |
| Flyway | enabled and disabled, to remove it as a factor |
The factory itself appears correctly wired:
org.springframework.boot.r2dbc.testcontainers.PostgresR2dbcContainerConnectionDetailsFactoryis present in
spring-boot-r2dbc-4.0.0.jar- it is registered in that jar's
META-INF/spring.factories - its generic parameter is
org.testcontainers.postgresql.PostgreSQLContainer— the exact class of the bean - its required class,
io.r2dbc.spi.ConnectionFactoryOptions, is on the test runtime classpath
(io.r2dbc:r2dbc-spi:1.0.0.RELEASE,org.postgresql:r2dbc-postgresql:1.1.1.RELEASE)
Note the jar also ships DeprecatedPostgresR2dbcContainerConnectionDetailsFactory, whose generic parameter is the
1.x org.testcontainers.containers.PostgreSQLContainer<?>. Neither path produced details in our testing.
spring-boot-testcontainers-4.0.0.jar itself contains no Postgres classes; the factories live in the
technology-specific modules, which may be relevant to how they are discovered.
Workaround
Publishing the connection as system properties from the container works, since system properties outrank
configuration files:
init {
CONTAINER.start()
System.setProperty("spring.r2dbc.url",
"r2dbc:postgresql://${CONTAINER.host}:${CONTAINER.firstMappedPort}/$DATABASE_NAME")
System.setProperty("spring.r2dbc.username", CONTAINER.username)
System.setProperty("spring.r2dbc.password", CONTAINER.password)
}
Notes
- The application is WebFlux with
spring.main.web-application-type: nonein the test profile. - Dependency versions are managed by
io.spring.dependency-management; theorg.testcontainerscoordinates are
not managed by it under Boot 4 and carry explicit versions. - We did not test the static-field /
@ImportTestcontainersstyle of declaring the container, only the
@Bean+@ServiceConnectionstyle shown above.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by tracing PostgresR2dbcContainerConnectionDetailsFactory and DeprecatedPostgresR2dbcContainerConnectionDetailsFactory in spring-boot-r2dbc-4.0.0, then inspect their spring.factories registration and how the @Bean plus @ServiceConnection path discovers factories. Reproduce the Kotlin configuration with an unreachable spring.r2dbc.url and add a regression test showing that R2dbcConnectionDetails is published and the container connection takes precedence.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, kotlin, postgresql, spring-boot
- Domain
- backend, databases, testing
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100