From 83fbdc6ea897a61f62182b26733a4036b198a7a4 Mon Sep 17 00:00:00 2001 From: artsiom Date: Wed, 8 Aug 2018 18:40:30 +0300 Subject: [PATCH 1/2] Fix NPE in FlywayEndpoint when migration.installedOn is null See gh-14019 --- .../boot/actuate/flyway/FlywayEndpoint.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/flyway/FlywayEndpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/flyway/FlywayEndpoint.java index f8a1c4f497..cad08560e7 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/flyway/FlywayEndpoint.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/flyway/FlywayEndpoint.java @@ -17,6 +17,7 @@ package org.springframework.boot.actuate.flyway; import java.time.Instant; +import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -38,6 +39,7 @@ import org.springframework.context.ApplicationContext; * @author EddĂș MelĂ©ndez * @author Phillip Webb * @author Andy Wilkinson + * @author Artsiom Yudovin * @since 2.0.0 */ @Endpoint(id = "flyway") @@ -164,9 +166,14 @@ public class FlywayEndpoint { this.script = info.getScript(); this.state = info.getState(); this.installedBy = info.getInstalledBy(); - this.installedOn = Instant.ofEpochMilli(info.getInstalledOn().getTime()); this.installedRank = info.getInstalledRank(); this.executionTime = info.getExecutionTime(); + this.installedOn = toEpochMilli(info.getInstalledOn()); + } + + private Instant toEpochMilli(Date installedOn) { + return (installedOn != null) ? Instant.ofEpochMilli(installedOn.getTime()) + : null; } private String nullSafeToString(Object obj) { From 27f5e46587071110673cf09bb65ae14bad96447d Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 9 Aug 2018 11:10:21 +0100 Subject: [PATCH 2/2] Polish "Fix NPE in FlywayEndpoint when migration.installedOn is null" Closes gh-14019 --- .../boot/actuate/flyway/FlywayEndpoint.java | 11 +++-- .../actuate/flyway/FlywayEndpointTests.java | 43 +++++++++++++++++-- .../resources/db/migration/V2__update.sql | 0 .../resources/db/migration/V3__update.sql | 0 4 files changed, 45 insertions(+), 9 deletions(-) create mode 100644 spring-boot-project/spring-boot-actuator/src/test/resources/db/migration/V2__update.sql create mode 100644 spring-boot-project/spring-boot-actuator/src/test/resources/db/migration/V3__update.sql diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/flyway/FlywayEndpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/flyway/FlywayEndpoint.java index cad08560e7..2a255e58ec 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/flyway/FlywayEndpoint.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/flyway/FlywayEndpoint.java @@ -168,18 +168,17 @@ public class FlywayEndpoint { this.installedBy = info.getInstalledBy(); this.installedRank = info.getInstalledRank(); this.executionTime = info.getExecutionTime(); - this.installedOn = toEpochMilli(info.getInstalledOn()); - } - - private Instant toEpochMilli(Date installedOn) { - return (installedOn != null) ? Instant.ofEpochMilli(installedOn.getTime()) - : null; + this.installedOn = nullSafeToInstant(info.getInstalledOn()); } private String nullSafeToString(Object obj) { return (obj != null) ? obj.toString() : null; } + private Instant nullSafeToInstant(Date date) { + return (date != null) ? Instant.ofEpochMilli(date.getTime()) : null; + } + public MigrationType getType() { return this.type; } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/flyway/FlywayEndpointTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/flyway/FlywayEndpointTests.java index 360d117b7c..6bea6e4b9a 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/flyway/FlywayEndpointTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/flyway/FlywayEndpointTests.java @@ -16,9 +16,13 @@ package org.springframework.boot.actuate.flyway; +import java.util.Map; + import org.junit.Test; +import org.springframework.boot.actuate.flyway.FlywayEndpoint.FlywayDescriptor; import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration; +import org.springframework.boot.autoconfigure.flyway.FlywayMigrationStrategy; import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.ApplicationContext; @@ -40,9 +44,28 @@ public class FlywayEndpointTests { @Test public void flywayReportIsProduced() { new ApplicationContextRunner().withUserConfiguration(Config.class) - .run((context) -> assertThat( - context.getBean(FlywayEndpoint.class).flywayBeans().getContexts() - .get(context.getId()).getFlywayBeans()).hasSize(1)); + .run((context) -> { + Map flywayBeans = context + .getBean(FlywayEndpoint.class).flywayBeans().getContexts() + .get(context.getId()).getFlywayBeans(); + assertThat(flywayBeans).hasSize(1); + assertThat(flywayBeans.values().iterator().next().getMigrations()) + .hasSize(3); + }); + } + + @Test + public void whenFlywayHasBeenBaselinedFlywayReportIsProduced() { + new ApplicationContextRunner() + .withUserConfiguration(BaselinedFlywayConfig.class, Config.class) + .run((context) -> { + Map flywayBeans = context + .getBean(FlywayEndpoint.class).flywayBeans().getContexts() + .get(context.getId()).getFlywayBeans(); + assertThat(flywayBeans).hasSize(1); + assertThat(flywayBeans.values().iterator().next().getMigrations()) + .hasSize(3); + }); } @Configuration @@ -56,4 +79,18 @@ public class FlywayEndpointTests { } + @Configuration + public static class BaselinedFlywayConfig { + + @Bean + public FlywayMigrationStrategy baseliningMigrationStrategy() { + return (flyway) -> { + flyway.setBaselineVersionAsString("2"); + flyway.baseline(); + flyway.migrate(); + }; + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator/src/test/resources/db/migration/V2__update.sql b/spring-boot-project/spring-boot-actuator/src/test/resources/db/migration/V2__update.sql new file mode 100644 index 0000000000..e69de29bb2 diff --git a/spring-boot-project/spring-boot-actuator/src/test/resources/db/migration/V3__update.sql b/spring-boot-project/spring-boot-actuator/src/test/resources/db/migration/V3__update.sql new file mode 100644 index 0000000000..e69de29bb2