Skip to content

Commit 8dcca5c

Browse files
committed
Update support for Spring Boot's DataSourceScriptDatabaseInitializer
1 parent 767d5b3 commit 8dcca5c

File tree

6 files changed

+127
-103
lines changed

6 files changed

+127
-103
lines changed

embedded-database-spring-test/src/main/java/io/zonky/test/db/config/EmbeddedDatabaseAutoConfiguration.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@
1818

1919
import io.zonky.test.db.flyway.FlywayDatabaseExtension;
2020
import io.zonky.test.db.flyway.FlywayPropertiesPostProcessor;
21-
import io.zonky.test.db.init.DataSourceScriptDatabaseExtension;
2221
import io.zonky.test.db.init.EmbeddedDatabaseInitializer;
2322
import io.zonky.test.db.init.ScriptDatabasePreparer;
23+
import io.zonky.test.db.init.SpringScriptDatabaseExtension;
2424
import io.zonky.test.db.liquibase.LiquibaseDatabaseExtension;
2525
import io.zonky.test.db.liquibase.LiquibasePropertiesPostProcessor;
2626
import io.zonky.test.db.provider.DatabaseProvider;
@@ -292,10 +292,10 @@ public BeanPostProcessor liquibasePropertiesPostProcessor() {
292292

293293
@Bean
294294
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
295-
@ConditionalOnClass(name = "org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer")
296-
@ConditionalOnMissingBean(name = "dataSourceScriptDatabaseExtension")
297-
public DataSourceScriptDatabaseExtension dataSourceScriptDatabaseExtension(Environment environment) {
298-
return new DataSourceScriptDatabaseExtension(environment);
295+
@ConditionalOnClass(name = "org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer")
296+
@ConditionalOnMissingBean(name = "springScriptDatabaseExtension")
297+
public SpringScriptDatabaseExtension springScriptDatabaseExtension(Environment environment) {
298+
return new SpringScriptDatabaseExtension(environment);
299299
}
300300

301301
@Bean

embedded-database-spring-test/src/main/java/io/zonky/test/db/init/DataSourceScriptDatabaseExtension.java

Lines changed: 0 additions & 76 deletions
This file was deleted.
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/*
2+
* Copyright 2025 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+
* http://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 io.zonky.test.db.init;
18+
19+
import io.zonky.test.db.context.DatabaseContext;
20+
import io.zonky.test.db.util.AopProxyUtils;
21+
import io.zonky.test.db.util.ReflectionUtils;
22+
import org.aopalliance.aop.Advice;
23+
import org.aopalliance.intercept.MethodInterceptor;
24+
import org.aopalliance.intercept.MethodInvocation;
25+
import org.springframework.aop.Advisor;
26+
import org.springframework.aop.framework.Advised;
27+
import org.springframework.aop.framework.AopInfrastructureBean;
28+
import org.springframework.aop.framework.ProxyFactory;
29+
import org.springframework.aop.support.NameMatchMethodPointcutAdvisor;
30+
import org.springframework.beans.factory.config.BeanPostProcessor;
31+
import org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer;
32+
import org.springframework.core.Ordered;
33+
import org.springframework.core.env.Environment;
34+
35+
import javax.sql.DataSource;
36+
37+
import static com.google.common.base.Preconditions.checkState;
38+
39+
public class SpringScriptDatabaseExtension implements BeanPostProcessor, Ordered {
40+
41+
private final boolean enabled;
42+
43+
public SpringScriptDatabaseExtension(Environment environment) {
44+
this.enabled = environment.getProperty("zonky.test.database.spring.optimized-sql-init.enabled", boolean.class, true);
45+
}
46+
47+
@Override
48+
public int getOrder() {
49+
return Ordered.HIGHEST_PRECEDENCE + 1;
50+
}
51+
52+
@Override
53+
public Object postProcessBeforeInitialization(Object bean, String beanName) {
54+
if (!enabled || bean instanceof AopInfrastructureBean) {
55+
return bean;
56+
}
57+
58+
if (bean instanceof AbstractScriptDatabaseInitializer) {
59+
AbstractScriptDatabaseInitializer initializer = (AbstractScriptDatabaseInitializer) bean;
60+
DataSource dataSource = ReflectionUtils.getField(initializer, "dataSource");
61+
DatabaseContext context = AopProxyUtils.getDatabaseContext(dataSource);
62+
63+
if (context != null) {
64+
if (bean instanceof Advised && !((Advised) bean).isFrozen()) {
65+
((Advised) bean).addAdvisor(0, createAdvisor(initializer));
66+
return bean;
67+
} else {
68+
ProxyFactory proxyFactory = new ProxyFactory(bean);
69+
proxyFactory.addAdvisor(createAdvisor(initializer));
70+
proxyFactory.setProxyTargetClass(true);
71+
return proxyFactory.getProxy();
72+
}
73+
}
74+
}
75+
76+
return bean;
77+
}
78+
79+
@Override
80+
public Object postProcessAfterInitialization(Object bean, String beanName) {
81+
return bean;
82+
}
83+
84+
protected Advisor createAdvisor(AbstractScriptDatabaseInitializer initializer) {
85+
Advice advice = new SpringScriptDatabaseExtensionInterceptor(initializer);
86+
NameMatchMethodPointcutAdvisor advisor = new NameMatchMethodPointcutAdvisor(advice);
87+
advisor.setMappedNames("afterPropertiesSet", "initializeDatabase");
88+
return advisor;
89+
}
90+
91+
protected static class SpringScriptDatabaseExtensionInterceptor implements MethodInterceptor {
92+
93+
private final AbstractScriptDatabaseInitializer initializer;
94+
95+
protected SpringScriptDatabaseExtensionInterceptor(AbstractScriptDatabaseInitializer initializer) {
96+
this.initializer = initializer;
97+
}
98+
99+
@Override
100+
public Object invoke(MethodInvocation invocation) throws Throwable {
101+
String methodName = invocation.getMethod().getName();
102+
if (!"afterPropertiesSet".equals(methodName) && !"initializeDatabase".equals(methodName)) {
103+
return invocation.proceed();
104+
}
105+
106+
DataSource dataSource = ReflectionUtils.getField(initializer, "dataSource");
107+
DatabaseContext context = AopProxyUtils.getDatabaseContext(dataSource);
108+
checkState(context != null, "Data source context cannot be resolved");
109+
110+
context.apply(new SpringScriptDatabasePreparer(initializer));
111+
112+
return null;
113+
}
114+
}
115+
}

embedded-database-spring-test/src/main/java/io/zonky/test/db/init/DataSourceScriptDatabasePreparer.java renamed to embedded-database-spring-test/src/main/java/io/zonky/test/db/init/SpringScriptDatabasePreparer.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@
1919
import com.cedarsoftware.util.DeepEquals;
2020
import io.zonky.test.db.preparer.DatabasePreparer;
2121
import io.zonky.test.db.util.ReflectionUtils;
22-
import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer;
23-
22+
import org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer;
2423
import org.springframework.util.ReflectionUtils.FieldFilter;
2524

2625
import javax.sql.DataSource;
@@ -33,17 +32,17 @@
3332

3433
import static org.springframework.util.ReflectionUtils.makeAccessible;
3534

36-
public class DataSourceScriptDatabasePreparer implements DatabasePreparer {
35+
public class SpringScriptDatabasePreparer implements DatabasePreparer {
3736

3837
private static final Set<String> EXCLUDED_FIELDS = new HashSet<>(Arrays.asList("dataSource", "resourceLoader"));
3938

4039
private static final FieldFilter FIELD_FILTER =
4140
field -> !Modifier.isStatic(field.getModifiers()) && !EXCLUDED_FIELDS.contains(field.getName());
4241

43-
private final DataSourceScriptDatabaseInitializer initializer;
42+
private final AbstractScriptDatabaseInitializer initializer;
4443
private final ThreadLocalDataSource threadLocalDataSource;
4544

46-
public DataSourceScriptDatabasePreparer(DataSourceScriptDatabaseInitializer initializer) {
45+
public SpringScriptDatabasePreparer(AbstractScriptDatabaseInitializer initializer) {
4746
this.initializer = initializer;
4847
this.threadLocalDataSource = new ThreadLocalDataSource();
4948
ReflectionUtils.setField(initializer, "dataSource", threadLocalDataSource);
@@ -68,7 +67,7 @@ public void prepare(DataSource dataSource) {
6867
public boolean equals(Object o) {
6968
if (this == o) return true;
7069
if (o == null || getClass() != o.getClass()) return false;
71-
DataSourceScriptDatabasePreparer that = (DataSourceScriptDatabasePreparer) o;
70+
SpringScriptDatabasePreparer that = (SpringScriptDatabasePreparer) o;
7271
if (initializer.getClass() != that.initializer.getClass()) return false;
7372
AtomicBoolean equal = new AtomicBoolean(true);
7473
org.springframework.util.ReflectionUtils.doWithFields(initializer.getClass(),

spring-boot-4-stubs/src/main/java/org/springframework/boot/jdbc/init/DataSourceScriptDatabaseInitializer.java renamed to spring-boot-4-stubs/src/main/java/org/springframework/boot/sql/init/AbstractScriptDatabaseInitializer.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
* https://github.com/spring-projects/spring-boot
88
*/
99

10-
package org.springframework.boot.jdbc.init;
10+
package org.springframework.boot.sql.init;
1111

12-
public class DataSourceScriptDatabaseInitializer {
12+
public class AbstractScriptDatabaseInitializer {
1313

1414
public boolean initializeDatabase() {
1515
return false;

spring-boot-4-stubs/src/main/java/org/springframework/boot/sql/init/DatabaseInitializationSettings.java

Lines changed: 0 additions & 14 deletions
This file was deleted.

0 commit comments

Comments
 (0)