Skip to content

Commit a27dfcb

Browse files
committed
Make R2DBC auto-config back off without a connection provider
Closes gh-26439
1 parent 2af2a02 commit a27dfcb

File tree

6 files changed

+136
-1
lines changed

6 files changed

+136
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright 2012-2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.r2dbc;
18+
19+
import io.r2dbc.spi.ConnectionFactory;
20+
21+
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
22+
import org.springframework.boot.diagnostics.AbstractFailureAnalyzer;
23+
import org.springframework.boot.diagnostics.FailureAnalysis;
24+
import org.springframework.core.Ordered;
25+
26+
/**
27+
* An {@link AbstractFailureAnalyzer} that produces failure analysis when a
28+
* {@link NoSuchBeanDefinitionException} for a {@link ConnectionFactory} bean is thrown
29+
* and there is no {@code META-INF/services/io.r2dbc.spi.ConnectionFactoryProvider}
30+
* resource on the classpath.
31+
*
32+
* @author Andy Wilkinson
33+
*/
34+
class NoConnectionFactoryBeanFailureAnalyzer extends AbstractFailureAnalyzer<NoSuchBeanDefinitionException>
35+
implements Ordered {
36+
37+
private final ClassLoader classLoader;
38+
39+
NoConnectionFactoryBeanFailureAnalyzer() {
40+
this(NoConnectionFactoryBeanFailureAnalyzer.class.getClassLoader());
41+
}
42+
43+
NoConnectionFactoryBeanFailureAnalyzer(ClassLoader classLoader) {
44+
this.classLoader = classLoader;
45+
}
46+
47+
@Override
48+
protected FailureAnalysis analyze(Throwable rootFailure, NoSuchBeanDefinitionException cause) {
49+
if (ConnectionFactory.class.equals(cause.getBeanType())
50+
&& this.classLoader.getResource("META-INF/services/io.r2dbc.spi.ConnectionFactoryProvider") == null) {
51+
return new FailureAnalysis("No R2DBC ConnectionFactory bean is available "
52+
+ "and no /META-INF/services/io.r2dbc.spi.ConnectionFactoryProvider resource could be found.",
53+
"Check that the R2DBC driver for your database is on the classpath.", cause);
54+
}
55+
return null;
56+
}
57+
58+
@Override
59+
public int getOrder() {
60+
return 0;
61+
}
62+
63+
}

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/r2dbc/R2dbcAutoConfiguration.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
2222
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
2323
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
24+
import org.springframework.boot.autoconfigure.condition.ConditionalOnResource;
2425
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
2526
import org.springframework.boot.autoconfigure.sql.init.SqlInitializationAutoConfiguration;
2627
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@@ -36,6 +37,7 @@
3637
*/
3738
@Configuration(proxyBeanMethods = false)
3839
@ConditionalOnClass(ConnectionFactory.class)
40+
@ConditionalOnResource(resources = "classpath:META-INF/services/io.r2dbc.spi.ConnectionFactoryProvider")
3941
@AutoConfigureBefore({ DataSourceAutoConfiguration.class, SqlInitializationAutoConfiguration.class })
4042
@EnableConfigurationProperties(R2dbcProperties.class)
4143
@Import({ ConnectionFactoryConfigurations.Pool.class, ConnectionFactoryConfigurations.Generic.class,

spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ org.springframework.boot.autoconfigure.jdbc.DataSourceBeanCreationFailureAnalyze
165165
org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer,\
166166
org.springframework.boot.autoconfigure.jooq.NoDslContextBeanFailureAnalyzer,\
167167
org.springframework.boot.autoconfigure.r2dbc.ConnectionFactoryBeanCreationFailureAnalyzer,\
168+
org.springframework.boot.autoconfigure.r2dbc.NoConnectionFactoryBeanFailureAnalyzer,\
168169
org.springframework.boot.autoconfigure.session.NonUniqueSessionRepositoryFailureAnalyzer
169170

170171
# Template availability providers
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright 2012-2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.r2dbc;
18+
19+
import io.r2dbc.spi.ConnectionFactory;
20+
import io.r2dbc.spi.ConnectionFactoryProvider;
21+
import org.junit.jupiter.api.Test;
22+
23+
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
24+
import org.springframework.boot.test.context.FilteredClassLoader;
25+
26+
import static org.assertj.core.api.Assertions.assertThat;
27+
28+
/**
29+
* Tests for {@link NoConnectionFactoryBeanFailureAnalyzer}.
30+
*
31+
* @author Andy Wilkinson
32+
*/
33+
class NoConnectionFactoryBeanFailureAnalyzerTests {
34+
35+
@Test
36+
void analyzeWhenNotNoSuchBeanDefinitionExceptionShouldReturnNull() {
37+
assertThat(new NoConnectionFactoryBeanFailureAnalyzer().analyze(new Exception())).isNull();
38+
}
39+
40+
@Test
41+
void analyzeWhenNoSuchBeanDefinitionExceptionForDifferentTypeShouldReturnNull() {
42+
assertThat(
43+
new NoConnectionFactoryBeanFailureAnalyzer().analyze(new NoSuchBeanDefinitionException(String.class)))
44+
.isNull();
45+
}
46+
47+
@Test
48+
void analyzeWhenNoSuchBeanDefinitionExceptionButProviderIsAvailableShouldReturnNull() {
49+
assertThat(new NoConnectionFactoryBeanFailureAnalyzer()
50+
.analyze(new NoSuchBeanDefinitionException(ConnectionFactory.class))).isNull();
51+
}
52+
53+
@Test
54+
void analyzeWhenNoSuchBeanDefinitionExceptionAndNoProviderShouldAnalyze() {
55+
assertThat(new NoConnectionFactoryBeanFailureAnalyzer(
56+
new FilteredClassLoader(("META-INF/services/" + ConnectionFactoryProvider.class.getName())::equals))
57+
.analyze(new NoSuchBeanDefinitionException(ConnectionFactory.class))).isNotNull();
58+
}
59+
60+
}

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/r2dbc/R2dbcAutoConfigurationTests.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import io.r2dbc.pool.ConnectionPool;
2929
import io.r2dbc.pool.PoolMetrics;
3030
import io.r2dbc.spi.ConnectionFactory;
31+
import io.r2dbc.spi.ConnectionFactoryProvider;
3132
import io.r2dbc.spi.Option;
3233
import io.r2dbc.spi.Wrapped;
3334
import org.assertj.core.api.InstanceOfAssertFactories;
@@ -255,6 +256,14 @@ void configureWithoutUrlAndEmbeddedCandidateFails() {
255256
});
256257
}
257258

259+
@Test
260+
void configureWithoutUrlAndNoConnectionFactoryProviderBacksOff() {
261+
this.contextRunner
262+
.withClassLoader(new FilteredClassLoader(
263+
("META-INF/services/" + ConnectionFactoryProvider.class.getName())::equals))
264+
.run((context) -> assertThat(context).doesNotHaveBean(R2dbcAutoConfiguration.class));
265+
}
266+
258267
@Test
259268
void configureWithDataSourceAutoConfigurationDoesNotCreateDataSource() {
260269
this.contextRunner.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))

spring-boot-project/spring-boot-starters/spring-boot-starter-jooq/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ plugins {
22
id "org.springframework.boot.starter"
33
}
44

5-
description = "Starter for using jOOQ to access SQL databases. An alternative to spring-boot-starter-data-jpa or spring-boot-starter-jdbc"
5+
description = "Starter for using jOOQ to access SQL databases with JDBC. An alternative to spring-boot-starter-data-jpa or spring-boot-starter-jdbc"
66

77
dependencies {
88
api(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-jdbc"))

0 commit comments

Comments
 (0)