From 8d27f4ee7cc029cfc6eec48144eb0bd77bd42a98 Mon Sep 17 00:00:00 2001 From: Yanming Zhou Date: Mon, 17 Feb 2025 15:53:17 +0800 Subject: [PATCH 1/2] Include non-default DataSource candidates This commit updates H2ConsoleAutoConfiguration to consider non-default data sources when logging connection URLs. See gh-44293 Signed-off-by: Yanming Zhou --- .../boot/autoconfigure/h2/H2ConsoleAutoConfiguration.java | 6 +++++- .../autoconfigure/h2/H2ConsoleAutoConfigurationTests.java | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/h2/H2ConsoleAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/h2/H2ConsoleAutoConfiguration.java index 78d7395dae0..278b5166bf2 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/h2/H2ConsoleAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/h2/H2ConsoleAutoConfiguration.java @@ -47,6 +47,7 @@ import org.springframework.core.log.LogMessage; * @author Marten Deinum * @author Stephane Nicoll * @author Phillip Webb + * @author Yanming Zhou * @since 1.3.0 */ @AutoConfiguration(after = DataSourceAutoConfiguration.class) @@ -113,7 +114,10 @@ public class H2ConsoleAutoConfiguration { } private List getConnectionUrls(ObjectProvider dataSources) { - return dataSources.orderedStream().map(this::getConnectionUrl).filter(Objects::nonNull).toList(); + return dataSources.orderedStream(ObjectProvider.UNFILTERED) + .map(this::getConnectionUrl) + .filter(Objects::nonNull) + .toList(); } private String getConnectionUrl(DataSource dataSource) { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/h2/H2ConsoleAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/h2/H2ConsoleAutoConfigurationTests.java index d577b59baed..8232f58930c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/h2/H2ConsoleAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/h2/H2ConsoleAutoConfigurationTests.java @@ -57,6 +57,7 @@ import static org.mockito.Mockito.mock; * @author Stephane Nicoll * @author Shraddha Yeole * @author Phillip Webb + * @author Yanming Zhou */ class H2ConsoleAutoConfigurationTests { @@ -206,7 +207,7 @@ class H2ConsoleAutoConfigurationTests { return mockDataSource("anotherJdbcUrl"); } - @Bean + @Bean(defaultCandidate = false) @Order(0) DataSource someDataSource() throws SQLException { return mockDataSource("someJdbcUrl"); From ceaf88c1a4daffa823ee8b41f9ed042f64818655 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Tue, 18 Feb 2025 11:11:57 +0100 Subject: [PATCH 2/2] Polish "Include non-default DataSource candidates" See gh-44293 --- .../h2/H2ConsoleAutoConfiguration.java | 3 +- .../h2/H2ConsoleAutoConfigurationTests.java | 65 +++++++++++++------ 2 files changed, 47 insertions(+), 21 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/h2/H2ConsoleAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/h2/H2ConsoleAutoConfiguration.java index 278b5166bf2..d76f1072479 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/h2/H2ConsoleAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/h2/H2ConsoleAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2024 the original author or authors. + * Copyright 2012-2025 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. @@ -47,7 +47,6 @@ import org.springframework.core.log.LogMessage; * @author Marten Deinum * @author Stephane Nicoll * @author Phillip Webb - * @author Yanming Zhou * @since 1.3.0 */ @AutoConfiguration(after = DataSourceAutoConfiguration.class) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/h2/H2ConsoleAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/h2/H2ConsoleAutoConfigurationTests.java index 8232f58930c..62816ee6740 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/h2/H2ConsoleAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/h2/H2ConsoleAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2024 the original author or authors. + * Copyright 2012-2025 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. @@ -57,7 +57,6 @@ import static org.mockito.Mockito.mock; * @author Stephane Nicoll * @author Shraddha Yeole * @author Phillip Webb - * @author Yanming Zhou */ class H2ConsoleAutoConfigurationTests { @@ -163,6 +162,17 @@ class H2ConsoleAutoConfigurationTests { "H2 console available at '/h2-console'. Databases available at 'someJdbcUrl', 'anotherJdbcUrl'")); } + @Test + @ExtendWith(OutputCaptureExtension.class) + void allDataSourceUrlsAreLoggedWhenNonCandidate(CapturedOutput output) { + ClassLoader webAppClassLoader = new URLClassLoader(new URL[0]); + this.contextRunner.withClassLoader(webAppClassLoader) + .withUserConfiguration(FailingDataSourceConfiguration.class, MultiDataSourceNonCandidateConfiguration.class) + .withPropertyValues("spring.h2.console.enabled=true") + .run((context) -> assertThat(output).contains( + "H2 console available at '/h2-console'. Databases available at 'someJdbcUrl', 'anotherJdbcUrl'")); + } + @Test void h2ConsoleShouldNotFailIfDatabaseConnectionFails() { this.contextRunner.withUserConfiguration(FailingDataSourceConfiguration.class) @@ -186,6 +196,20 @@ class H2ConsoleAutoConfigurationTests { }); } + private static DataSource mockDataSource(String url, ClassLoader classLoader) throws SQLException { + DataSource dataSource = mock(DataSource.class); + given(dataSource.getConnection()).will((invocation) -> { + assertThat(Thread.currentThread().getContextClassLoader()).isEqualTo(classLoader); + Connection connection = mock(Connection.class); + DatabaseMetaData metadata = mock(DatabaseMetaData.class); + given(connection.getMetaData()).willReturn(metadata); + given(metadata.getURL()).willReturn(url); + return connection; + }); + + return dataSource; + } + @Configuration(proxyBeanMethods = false) static class FailingDataSourceConfiguration { @@ -204,27 +228,30 @@ class H2ConsoleAutoConfigurationTests { @Bean @Order(5) DataSource anotherDataSource() throws SQLException { - return mockDataSource("anotherJdbcUrl"); + return mockDataSource("anotherJdbcUrl", getClass().getClassLoader()); + } + + @Bean + @Order(0) + DataSource someDataSource() throws SQLException { + return mockDataSource("someJdbcUrl", getClass().getClassLoader()); + } + + } + + @Configuration(proxyBeanMethods = false) + static class MultiDataSourceNonCandidateConfiguration { + + @Bean + @Order(5) + DataSource anotherDataSource() throws SQLException { + return mockDataSource("anotherJdbcUrl", getClass().getClassLoader()); } @Bean(defaultCandidate = false) @Order(0) - DataSource someDataSource() throws SQLException { - return mockDataSource("someJdbcUrl"); - } - - private DataSource mockDataSource(String url) throws SQLException { - DataSource dataSource = mock(DataSource.class); - given(dataSource.getConnection()).will((invocation) -> { - assertThat(Thread.currentThread().getContextClassLoader()).isEqualTo(getClass().getClassLoader()); - Connection connection = mock(Connection.class); - DatabaseMetaData metadata = mock(DatabaseMetaData.class); - given(connection.getMetaData()).willReturn(metadata); - given(metadata.getURL()).willReturn(url); - return connection; - }); - - return dataSource; + DataSource nonDefaultDataSource() throws SQLException { + return mockDataSource("someJdbcUrl", getClass().getClassLoader()); } }