Skip to content

Commit 4aa9835

Browse files
Improve datasource unwrapping for flyway autoconfiguration (#102)
1 parent 8cc857b commit 4aa9835

File tree

3 files changed

+50
-0
lines changed

3 files changed

+50
-0
lines changed

datasource-decorator-spring-boot-autoconfigure/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ dependencies {
4242
testImplementation("org.apache.commons:commons-dbcp2:2.9.0")
4343
testImplementation("org.apache.tomcat:tomcat-jdbc:10.1.5")
4444
testImplementation("com.zaxxer:HikariCP:5.0.1")
45+
testImplementation("org.flywaydb:flyway-core:9.5.1")
4546
}
4647

4748
tasks {

datasource-decorator-spring-boot-autoconfigure/src/main/java/com/github/gavlyukovskiy/boot/jdbc/decorator/DecoratedDataSource.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import javax.sql.DataSource;
2222

23+
import java.sql.SQLException;
2324
import java.util.List;
2425
import java.util.stream.Collectors;
2526

@@ -83,6 +84,24 @@ public List<DataSourceDecorationStage> getDecoratingChain() {
8384
return decoratingChain;
8485
}
8586

87+
@Override
88+
@SuppressWarnings("unchecked")
89+
public <T> T unwrap(Class<T> iface) throws SQLException {
90+
// Spring Boot unwrapping simply passes 'unwrap(DataSource.class)' expecting real datasource to be returned
91+
// if the real datasource type matches - return real datasource
92+
if (iface.isInstance(getRealDataSource())) {
93+
return (T) getRealDataSource();
94+
}
95+
// As some decorators don't consider their types during unwrapping
96+
// if their type is specifically requested, we can return the decorator itself
97+
for (DataSourceDecorationStage dataSourceDecorationStage : decoratingChain) {
98+
if (iface.isInstance(dataSourceDecorationStage.getDataSource())) {
99+
return (T) dataSourceDecorationStage.getDataSource();
100+
}
101+
}
102+
return super.unwrap(iface);
103+
}
104+
86105
@Override
87106
public String toString() {
88107
return decoratingChain.stream()

datasource-decorator-spring-boot-autoconfigure/src/test/java/com/github/gavlyukovskiy/boot/jdbc/decorator/DataSourceDecoratorAutoConfigurationTests.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.springframework.beans.DirectFieldAccessor;
2828
import org.springframework.boot.autoconfigure.AutoConfigurations;
2929
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
30+
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration;
3031
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
3132
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
3233
import org.springframework.context.annotation.Bean;
@@ -254,6 +255,35 @@ void testRoutingDataSourceIsNotDecorated() {
254255
});
255256
}
256257

258+
@Test
259+
void testUnwrapsRealDataSourceForFlyway() {
260+
ApplicationContextRunner contextRunner = this.contextRunner
261+
.withConfiguration(AutoConfigurations.of(FlywayAutoConfiguration.class))
262+
.withPropertyValues("spring.flyway.user=sa");
263+
264+
contextRunner.run(context -> {
265+
DataSource dataSource = context.getBean(DataSource.class);
266+
assertThat(dataSource).isInstanceOf(DecoratedDataSource.class);
267+
assertThat(dataSource.unwrap(HikariDataSource.class)).isInstanceOf(HikariDataSource.class);
268+
assertThat(dataSource.unwrap(DataSource.class)).isInstanceOf(HikariDataSource.class);
269+
});
270+
}
271+
272+
@Test
273+
void testUnwrapsProxyDataSourcesFromChain() {
274+
ApplicationContextRunner contextRunner = this.contextRunner
275+
.withConfiguration(AutoConfigurations.of(FlywayAutoConfiguration.class))
276+
.withPropertyValues("spring.flyway.user=sa");
277+
278+
contextRunner.run(context -> {
279+
DataSource dataSource = context.getBean(DataSource.class);
280+
assertThat(dataSource).isInstanceOf(DecoratedDataSource.class);
281+
assertThat(dataSource.unwrap(ProxyDataSource.class)).isInstanceOf(ProxyDataSource.class);
282+
assertThat(dataSource.unwrap(P6DataSource.class)).isInstanceOf(P6DataSource.class);
283+
assertThat(dataSource.unwrap(FlexyPoolDataSource.class)).isInstanceOf(FlexyPoolDataSource.class);
284+
});
285+
}
286+
257287
private AbstractListAssert<?, List<?>, Object, ObjectAssert<Object>> assertThatDataSourceDecoratingChain(DataSource dataSource) {
258288
return assertThat(((DecoratedDataSource) dataSource).getDecoratingChain()).extracting("dataSource").extracting("class");
259289
}

0 commit comments

Comments
 (0)