From a270c13d6f75b2516dccd4034c0614e65d06ee69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez?= Date: Tue, 1 Mar 2016 22:40:56 +1000 Subject: [PATCH 1/2] Upgrade to Flyway 4.0 Closes gh-5344 --- .../flyway/FlywayAutoConfiguration.java | 11 ++++- .../flyway/FlywayAutoConfigurationTests.java | 42 +++++++++++++++++++ spring-boot-dependencies/pom.xml | 2 +- 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java index 8c474f81ff..db045bf800 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java @@ -26,6 +26,7 @@ import javax.sql.DataSource; import org.flywaydb.core.Flyway; import org.flywaydb.core.api.MigrationVersion; +import org.flywaydb.core.api.callback.FlywayCallback; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfigureAfter; @@ -61,6 +62,7 @@ import org.springframework.util.ObjectUtils; * @author Vedran Pavic * @author Stephane Nicoll * @author Jacques-Etienne Beaudet + * @author Eddú Meléndez * @since 1.1.0 */ @Configuration @@ -92,15 +94,19 @@ public class FlywayAutoConfiguration { private final FlywayMigrationStrategy migrationStrategy; + private FlywayCallback[] flywayCallbacks; + public FlywayConfiguration(FlywayProperties properties, ResourceLoader resourceLoader, ObjectProvider dataSource, @FlywayDataSource ObjectProvider flywayDataSource, - ObjectProvider migrationStrategy) { + ObjectProvider migrationStrategy, + ObjectProvider flywayCallbacks) { this.properties = properties; this.resourceLoader = resourceLoader; this.dataSource = dataSource.getIfUnique(); this.flywayDataSource = flywayDataSource.getIfAvailable(); this.migrationStrategy = migrationStrategy.getIfAvailable(); + this.flywayCallbacks = flywayCallbacks.getIfAvailable(); } @PostConstruct @@ -140,6 +146,9 @@ public class FlywayAutoConfiguration { else { flyway.setDataSource(this.dataSource); } + if (this.flywayCallbacks != null && this.flywayCallbacks.length > 0) { + flyway.setCallbacks(this.flywayCallbacks); + } flyway.setLocations(this.properties.getLocations().toArray(new String[0])); return flyway; } diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfigurationTests.java index f01bbe957c..70d3abbeaa 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfigurationTests.java @@ -25,6 +25,7 @@ import javax.sql.DataSource; import org.flywaydb.core.Flyway; import org.flywaydb.core.api.MigrationVersion; +import org.flywaydb.core.api.callback.BaseFlywayCallback; import org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform; import org.junit.After; import org.junit.Before; @@ -57,6 +58,7 @@ import static org.assertj.core.api.Assertions.assertThat; * @author Phillip Webb * @author Andy Wilkinson * @author Vedran Pavic + * @author Eddú Meléndez */ public class FlywayAutoConfigurationTests { @@ -202,6 +204,16 @@ public class FlywayAutoConfigurationTests { assertThat(initializer.getOrder()).isEqualTo(Ordered.HIGHEST_PRECEDENCE); } + @Test + public void customFlywayCallback() throws Exception { + registerAndRefresh(EmbeddedDataSourceConfiguration.class, + FlywayAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class, + MockOneFlywayCallback.class, MockTwoFlywayCallback.class); + assertThat(this.context.getBean(Flyway.class)).isNotNull(); + this.context.getBean(MockOneFlywayCallback.class).assertCalled(); + this.context.getBean(MockTwoFlywayCallback.class).assertCalled(); + } + @Test public void customFlywayWithJpa() throws Exception { registerAndRefresh(CustomFlywayWithJpaConfiguration.class, @@ -325,4 +337,34 @@ public class FlywayAutoConfigurationTests { } + @Component + protected static class MockOneFlywayCallback + extends BaseFlywayCallback { + + private boolean called = false; + + public MockOneFlywayCallback() { + this.called = true; + } + + public void assertCalled() { + assertThat(this.called).isTrue(); + } + } + + @Component + protected static class MockTwoFlywayCallback + extends BaseFlywayCallback { + + private boolean called = false; + + public MockTwoFlywayCallback() { + this.called = true; + } + + public void assertCalled() { + assertThat(this.called).isTrue(); + } + } + } diff --git a/spring-boot-dependencies/pom.xml b/spring-boot-dependencies/pom.xml index f6b56c60f6..6460e1383f 100644 --- a/spring-boot-dependencies/pom.xml +++ b/spring-boot-dependencies/pom.xml @@ -73,7 +73,7 @@ 2.10.3 3.2.0 1.50.5 - 3.2.1 + 4.0.3 2.3.25-incubating 2.4.4 3.0.0 From 4ea7dc6f31ec19369f1d08dd85ddbcd38165708e Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 30 Jan 2017 10:48:36 +0000 Subject: [PATCH 2/2] Polish "Upgrade to Flyway 4.0" See gh-5344 --- .../flyway/FlywayAutoConfiguration.java | 15 ++-- .../flyway/FlywayAutoConfigurationTests.java | 68 +++++++++---------- spring-boot-docs/src/main/asciidoc/howto.adoc | 8 ++- 3 files changed, 48 insertions(+), 43 deletions(-) diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java index db045bf800..c5397983be 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2016 the original author or authors. + * Copyright 2012-2017 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. @@ -18,6 +18,7 @@ package org.springframework.boot.autoconfigure.flyway; import java.util.Collections; import java.util.HashSet; +import java.util.List; import java.util.Set; import javax.annotation.PostConstruct; @@ -94,19 +95,20 @@ public class FlywayAutoConfiguration { private final FlywayMigrationStrategy migrationStrategy; - private FlywayCallback[] flywayCallbacks; + private List flywayCallbacks; public FlywayConfiguration(FlywayProperties properties, ResourceLoader resourceLoader, ObjectProvider dataSource, @FlywayDataSource ObjectProvider flywayDataSource, ObjectProvider migrationStrategy, - ObjectProvider flywayCallbacks) { + ObjectProvider> flywayCallbacks) { this.properties = properties; this.resourceLoader = resourceLoader; this.dataSource = dataSource.getIfUnique(); this.flywayDataSource = flywayDataSource.getIfAvailable(); this.migrationStrategy = migrationStrategy.getIfAvailable(); - this.flywayCallbacks = flywayCallbacks.getIfAvailable(); + this.flywayCallbacks = flywayCallbacks + .getIfAvailable(() -> Collections.emptyList()); } @PostConstruct @@ -146,9 +148,8 @@ public class FlywayAutoConfiguration { else { flyway.setDataSource(this.dataSource); } - if (this.flywayCallbacks != null && this.flywayCallbacks.length > 0) { - flyway.setCallbacks(this.flywayCallbacks); - } + flyway.setCallbacks(this.flywayCallbacks + .toArray(new FlywayCallback[this.flywayCallbacks.size()])); flyway.setLocations(this.properties.getLocations().toArray(new String[0])); return flyway; } diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfigurationTests.java index 70d3abbeaa..4a0658c57f 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfigurationTests.java @@ -16,6 +16,7 @@ package org.springframework.boot.autoconfigure.flyway; +import java.sql.Connection; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; @@ -25,13 +26,14 @@ import javax.sql.DataSource; import org.flywaydb.core.Flyway; import org.flywaydb.core.api.MigrationVersion; -import org.flywaydb.core.api.callback.BaseFlywayCallback; +import org.flywaydb.core.api.callback.FlywayCallback; import org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.mockito.InOrder; import org.springframework.beans.factory.BeanCreationException; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; @@ -44,12 +46,16 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; import org.springframework.core.env.MapPropertySource; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; import org.springframework.stereotype.Component; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.mock; /** * Tests for {@link FlywayAutoConfiguration}. @@ -204,16 +210,6 @@ public class FlywayAutoConfigurationTests { assertThat(initializer.getOrder()).isEqualTo(Ordered.HIGHEST_PRECEDENCE); } - @Test - public void customFlywayCallback() throws Exception { - registerAndRefresh(EmbeddedDataSourceConfiguration.class, - FlywayAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class, - MockOneFlywayCallback.class, MockTwoFlywayCallback.class); - assertThat(this.context.getBean(Flyway.class)).isNotNull(); - this.context.getBean(MockOneFlywayCallback.class).assertCalled(); - this.context.getBean(MockTwoFlywayCallback.class).assertCalled(); - } - @Test public void customFlywayWithJpa() throws Exception { registerAndRefresh(CustomFlywayWithJpaConfiguration.class, @@ -258,6 +254,23 @@ public class FlywayAutoConfigurationTests { "classpath:db/vendors/h2", "classpath:db/changelog"); } + @Test + public void callbacksAreConfiguredAndOrdered() throws Exception { + registerAndRefresh(EmbeddedDataSourceConfiguration.class, + FlywayAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class, + CallbackConfiguration.class); + assertThat(this.context.getBeansOfType(Flyway.class)).hasSize(1); + Flyway flyway = this.context.getBean(Flyway.class); + FlywayCallback callbackOne = this.context.getBean("callbackOne", + FlywayCallback.class); + FlywayCallback callbackTwo = this.context.getBean("callbackTwo", + FlywayCallback.class); + assertThat(flyway.getCallbacks()).containsExactly(callbackTwo, callbackOne); + InOrder orderedCallbacks = inOrder(callbackOne, callbackTwo); + orderedCallbacks.verify(callbackTwo).beforeMigrate(any(Connection.class)); + orderedCallbacks.verify(callbackOne).beforeMigrate(any(Connection.class)); + } + private void registerAndRefresh(Class... annotatedClasses) { this.context.register(annotatedClasses); this.context.refresh(); @@ -337,34 +350,21 @@ public class FlywayAutoConfigurationTests { } - @Component - protected static class MockOneFlywayCallback - extends BaseFlywayCallback { - - private boolean called = false; - - public MockOneFlywayCallback() { - this.called = true; - } + @Configuration + static class CallbackConfiguration { - public void assertCalled() { - assertThat(this.called).isTrue(); + @Bean + @Order(1) + public FlywayCallback callbackOne() { + return mock(FlywayCallback.class); } - } - - @Component - protected static class MockTwoFlywayCallback - extends BaseFlywayCallback { - - private boolean called = false; - public MockTwoFlywayCallback() { - this.called = true; + @Bean + @Order(0) + public FlywayCallback callbackTwo() { + return mock(FlywayCallback.class); } - public void assertCalled() { - assertThat(this.called).isTrue(); - } } } diff --git a/spring-boot-docs/src/main/asciidoc/howto.adoc b/spring-boot-docs/src/main/asciidoc/howto.adoc index 95c65a4eeb..c3a16e508f 100644 --- a/spring-boot-docs/src/main/asciidoc/howto.adoc +++ b/spring-boot-docs/src/main/asciidoc/howto.adoc @@ -1952,8 +1952,12 @@ Boot will call `Flyway.migrate()` to perform the database migration. If you woul more control, provide a `@Bean` that implements {sc-spring-boot-autoconfigure}/flyway/FlywayMigrationStrategy.{sc-ext}[`FlywayMigrationStrategy`]. -TIP: If you want to make use of http://flywaydb.org/documentation/callbacks.html[Flyway -callbacks], those scripts should also live in the `classpath:db/migration` folder. +Flyway supports SQL and Java http://flywaydb.org/documentation/callbacks.html[callbacks]. +To use SQL-based callbacks, place the callback scripts in the `classpath:db/migration` +folder. To use Java-based callbacks, create one or more beans that implement +`FlywayCallback` or, preferably, extend `BaseFlywayCallback`. Any such beans will be +automatically registered with `Flyway`. They can be ordered using `@Order` or by +implementing `Ordered`. By default Flyway will autowire the (`@Primary`) `DataSource` in your context and use that for migrations. If you like to use a different `DataSource` you can create