From 8d241d87e619e7377f1c4100231b1cf111f960dc Mon Sep 17 00:00:00 2001 From: Safeer A Date: Tue, 17 Aug 2021 01:49:43 +0400 Subject: [PATCH 1/3] Fixing the NullPointerException in RoutingDataSourceHealthContributor The RoutingDataSourceHealthContributor constructor throws a NullPointerException (NPE) if the provided map has a null key. With this commit the NPE issue has been fixed by filtering the entries that are not-null. This closes #27694 --- .../jdbc/DataSourceHealthContributorAutoConfiguration.java | 1 + 1 file changed, 1 insertion(+) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/jdbc/DataSourceHealthContributorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/jdbc/DataSourceHealthContributorAutoConfiguration.java index be84c6efa790..2b4f96ff25fc 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/jdbc/DataSourceHealthContributorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/jdbc/DataSourceHealthContributorAutoConfiguration.java @@ -127,6 +127,7 @@ static class RoutingDataSourceHealthContributor implements CompositeHealthContri RoutingDataSourceHealthContributor(AbstractRoutingDataSource routingDataSource, Function contributorFunction) { Map routedDataSources = routingDataSource.getResolvedDataSources().entrySet().stream() + .filter((e) -> e.getKey() != null) .collect(Collectors.toMap((e) -> e.getKey().toString(), Map.Entry::getValue)); this.delegate = CompositeHealthContributor.fromMap(routedDataSources, contributorFunction); } From e9699e54cf6ff085a12807dccc3c1b32608e1a7c Mon Sep 17 00:00:00 2001 From: Safeer A Date: Tue, 17 Aug 2021 02:04:08 +0400 Subject: [PATCH 2/3] Author added Updating the file author as per the commit message guide --- .../jdbc/DataSourceHealthContributorAutoConfiguration.java | 1 + 1 file changed, 1 insertion(+) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/jdbc/DataSourceHealthContributorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/jdbc/DataSourceHealthContributorAutoConfiguration.java index 2b4f96ff25fc..4408ea00977e 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/jdbc/DataSourceHealthContributorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/jdbc/DataSourceHealthContributorAutoConfiguration.java @@ -57,6 +57,7 @@ * @author Stephane Nicoll * @author Arthur Kalimullin * @author Julio Gomez + * @author Safeer Ansari * @since 2.0.0 */ @Configuration(proxyBeanMethods = false) From 05ba62915c249e951a346d51b506a8974c244f55 Mon Sep 17 00:00:00 2001 From: Safeer A Date: Tue, 17 Aug 2021 03:46:32 +0400 Subject: [PATCH 3/3] Saving the datasource in map with null key as 'unnamed' Instead of throwing an exception, the datasource will be saved as 'unnamed' in the map. In this commit, the 'unnamed' key has been added, along with the required tests --- .../jdbc/DataSourceHealthContributorAutoConfiguration.java | 7 +++++-- .../DataSourceHealthContributorAutoConfigurationTests.java | 5 ++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/jdbc/DataSourceHealthContributorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/jdbc/DataSourceHealthContributorAutoConfiguration.java index 4408ea00977e..aeb078580007 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/jdbc/DataSourceHealthContributorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/jdbc/DataSourceHealthContributorAutoConfiguration.java @@ -19,6 +19,7 @@ import java.util.Collection; import java.util.Iterator; import java.util.Map; +import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; @@ -125,11 +126,13 @@ static class RoutingDataSourceHealthContributor implements CompositeHealthContri private final CompositeHealthContributor delegate; + private static final String UNNAMED_DATASOURCE_KEY = "unnamed"; + RoutingDataSourceHealthContributor(AbstractRoutingDataSource routingDataSource, Function contributorFunction) { Map routedDataSources = routingDataSource.getResolvedDataSources().entrySet().stream() - .filter((e) -> e.getKey() != null) - .collect(Collectors.toMap((e) -> e.getKey().toString(), Map.Entry::getValue)); + .collect(Collectors.toMap((e) -> Optional.ofNullable(e.getKey()).map(Object::toString) + .orElse(UNNAMED_DATASOURCE_KEY), Map.Entry::getValue)); this.delegate = CompositeHealthContributor.fromMap(routedDataSources, contributorFunction); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/jdbc/DataSourceHealthContributorAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/jdbc/DataSourceHealthContributorAutoConfigurationTests.java index 91d7eac8e534..2d86bf1f989f 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/jdbc/DataSourceHealthContributorAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/jdbc/DataSourceHealthContributorAutoConfigurationTests.java @@ -49,6 +49,7 @@ * * @author Phillip Webb * @author Julio Gomez + * @author Safeer Ansari */ class DataSourceHealthContributorAutoConfigurationTests { @@ -102,10 +103,11 @@ void runWithOnlyRoutingDataSourceShouldIncludeRoutingDataSourceWithComposedIndic assertThat(context).hasSingleBean(RoutingDataSourceHealthContributor.class); RoutingDataSourceHealthContributor routingHealthContributor = context .getBean(RoutingDataSourceHealthContributor.class); + assertThat(routingHealthContributor.getContributor("unnamed")).isInstanceOf(DataSourceHealthIndicator.class); assertThat(routingHealthContributor.getContributor("one")).isInstanceOf(DataSourceHealthIndicator.class); assertThat(routingHealthContributor.getContributor("two")).isInstanceOf(DataSourceHealthIndicator.class); assertThat(routingHealthContributor.iterator()).toIterable().extracting("name") - .containsExactlyInAnyOrder("one", "two"); + .containsExactlyInAnyOrder("unnamed", "one", "two"); }); } @@ -155,6 +157,7 @@ static class RoutingDataSourceConfig { @Bean AbstractRoutingDataSource routingDataSource() { Map dataSources = new HashMap<>(); + dataSources.put(null, mock(DataSource.class)); dataSources.put("one", mock(DataSource.class)); dataSources.put("two", mock(DataSource.class)); AbstractRoutingDataSource routingDataSource = mock(AbstractRoutingDataSource.class);