From 364f014e9afb7e0ec097ff7632bfd585e7a2f550 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 21 Nov 2024 17:58:57 +0000 Subject: [PATCH 001/203] Next development version (v3.4.1-SNAPSHOT) --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 343ccc66d5d1..813f112d99db 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=3.4.0-SNAPSHOT +version=3.4.1-SNAPSHOT latestVersion=true spring.build-type=oss From fa0a4849fad6bb55f2faa32d2d19ac514c7ee345 Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Thu, 21 Nov 2024 23:33:49 +0900 Subject: [PATCH 002/203] Update Javadoc since for OtlpMetricsProperties and OtlpTracingProperties See gh-43249 --- .../metrics/export/otlp/OtlpMetricsProperties.java | 2 +- .../autoconfigure/tracing/otlp/OtlpTracingProperties.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpMetricsProperties.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpMetricsProperties.java index 17e5fe771a27..257a8ce3ef0e 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpMetricsProperties.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpMetricsProperties.java @@ -32,7 +32,7 @@ * * @author Eddú Meléndez * @author Jonatan Ivanov - * @since 3.0.0 + * @since 3.4.0 */ @ConfigurationProperties(prefix = "management.otlp.metrics.export") public class OtlpMetricsProperties extends StepRegistryProperties { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpTracingProperties.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpTracingProperties.java index 6ebbdb2cf7b6..2fa1a1232e7e 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpTracingProperties.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpTracingProperties.java @@ -26,7 +26,7 @@ * Configuration properties for exporting traces using OTLP. * * @author Jonatan Ivanov - * @since 3.1.0 + * @since 3.4.0 */ @ConfigurationProperties("management.otlp.tracing") public class OtlpTracingProperties { From 333762fd0e17a7f79ac4c9536b6242557b21a86d Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 22 Nov 2024 11:29:28 +0000 Subject: [PATCH 003/203] Upgrade to Gradle 8.11.1 Closes gh-43261 --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 94113f200e61..e2847c820046 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From 31cca9b5ad97d8f36efe2078936c37b16bcd4d35 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 22 Nov 2024 11:38:39 +0000 Subject: [PATCH 004/203] Upgrade Java version in .sdkmanrc to 17.0.13 Closes gh-43262 --- .sdkmanrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.sdkmanrc b/.sdkmanrc index 828308d277ec..eb2990e97224 100644 --- a/.sdkmanrc +++ b/.sdkmanrc @@ -1,3 +1,3 @@ # Enable auto-env through the sdkman_auto_env config # Add key=value pairs of SDKs to use below -java=17.0.12-librca +java=17.0.13-librca From 46f59c7ad01a4f23b818169caeb132bf873c1ff7 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 22 Nov 2024 11:43:19 +0000 Subject: [PATCH 005/203] Upgrade to release verification tests 0.0.7 Closes gh-43251 --- .github/workflows/verify.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index 181e7639417a..e9f67a2f0fa2 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -38,7 +38,7 @@ jobs: - name: Check Out Release Verification Tests uses: actions/checkout@v4 with: - ref: 'v0.0.6' + ref: 'v0.0.7' repository: spring-projects/spring-boot-release-verification token: ${{ secrets.token }} - name: Check Out Send Notification Action From 69100b7dd73ce0ea5e929cca02678a05c3406b44 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 22 Nov 2024 11:44:32 +0000 Subject: [PATCH 006/203] Set 3.3.x CLI release to no longer be the default on SDKMAN Closes gh-43246 --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4e64624c646c..de84836325df 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -117,7 +117,7 @@ jobs: - name: Publish to SDKMAN! uses: ./.github/actions/publish-to-sdkman with: - make-default: true + make-default: false sdkman-consumer-key: ${{ secrets.SDKMAN_CONSUMER_KEY }} sdkman-consumer-token: ${{ secrets.SDKMAN_CONSUMER_TOKEN }} spring-boot-version: ${{ needs.build-and-stage-release.outputs.version }} From c36d307f6a38b5d31c7b65cab831ffb1eb84a4c9 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 22 Nov 2024 11:47:42 +0000 Subject: [PATCH 007/203] Correct snapshot repository name for publishing commercial builds Closes gh-43250 --- .github/workflows/build-and-deploy-snapshot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-deploy-snapshot.yml b/.github/workflows/build-and-deploy-snapshot.yml index 7b5b3c9c87cc..406bae370220 100644 --- a/.github/workflows/build-and-deploy-snapshot.yml +++ b/.github/workflows/build-and-deploy-snapshot.yml @@ -31,7 +31,7 @@ jobs: folder: 'deployment-repository' password: ${{ vars.COMMERCIAL && secrets.COMMERCIAL_ARTIFACTORY_PASSWORD || secrets.ARTIFACTORY_PASSWORD }} project: ${{ vars.COMMERCIAL && 'spring' }} - repository: ${{ vars.COMMERCIAL && 'spring-commercial-snapshot-local' || 'libs-snapshot-local' }} + repository: ${{ vars.COMMERCIAL && 'spring-enterprise-maven-dev-local' || 'libs-snapshot-local' }} signing-key: ${{ secrets.GPG_PRIVATE_KEY }} signing-passphrase: ${{ secrets.GPG_PASSPHRASE }} uri: ${{ vars.COMMERCIAL_DEPLOY_REPO_URL || 'https://repo.spring.io' }} From cf1dadf2e7381f3fa831692a5dab6baab5fbd202 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 22 Nov 2024 11:58:50 +0000 Subject: [PATCH 008/203] Stop publishing CLI's Homebrew formula in commercial builds Closes gh-43247 --- .../spring-boot-cli/build.gradle | 34 +++++++++++++------ 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/spring-boot-project/spring-boot-tools/spring-boot-cli/build.gradle b/spring-boot-project/spring-boot-tools/spring-boot-cli/build.gradle index 312efac14343..15adb4f29b12 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-cli/build.gradle +++ b/spring-boot-project/spring-boot-tools/spring-boot-cli/build.gradle @@ -1,3 +1,6 @@ +import org.springframework.boot.build.properties.BuildProperties +import org.springframework.boot.build.properties.BuildType + plugins { id "java" id "eclipse" @@ -104,17 +107,27 @@ task tar(type: Tar) { configureArchive it } -task homebrewFormula(type: org.springframework.boot.build.cli.HomebrewFormula) { - dependsOn tar - outputDir = layout.buildDirectory.dir("homebrew") - template = file("src/main/homebrew/spring-boot.rb") - archive = tar.archiveFile -} +if (BuildProperties.get(project).buildType() == BuildType.OPEN_SOURCE) { + task homebrewFormula(type: org.springframework.boot.build.cli.HomebrewFormula) { + dependsOn tar + outputDir = layout.buildDirectory.dir("homebrew") + template = file("src/main/homebrew/spring-boot.rb") + archive = tar.archiveFile + } -def homebrewFormulaArtifact = artifacts.add("archives", file(layout.buildDirectory.file("homebrew/spring-boot.rb"))) { - type "rb" - classifier "homebrew" - builtBy "homebrewFormula" + def homebrewFormulaArtifact = artifacts.add("archives", file(layout.buildDirectory.file("homebrew/spring-boot.rb"))) { + type "rb" + classifier "homebrew" + builtBy "homebrewFormula" + } + + publishing { + publications { + getByName("maven") { + artifact homebrewFormulaArtifact + } + } + } } publishing { @@ -123,7 +136,6 @@ publishing { artifact fullJar artifact tar artifact zip - artifact homebrewFormulaArtifact } } } From bb3651b7d1c4334d5c350a9b127729aac2bfbf10 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 22 Nov 2024 14:42:48 +0000 Subject: [PATCH 009/203] Reduce warnings reported by Eclipse Closes gh-43269 --- ...althContributorAutoConfigurationTests.java | 3 +- ...althContributorAutoConfigurationTests.java | 3 +- ...onfigurationsSenderConfigurationTests.java | 2 + ...ToolsDataSourceAutoConfigurationTests.java | 39 +++--- ...ooledDataSourceAutoConfigurationTests.java | 119 ++++++++++-------- .../DevToolsR2dbcAutoConfigurationTests.java | 32 ++--- .../AbstractApplicationContextRunner.java | 4 +- .../AssertableApplicationContextTests.java | 3 +- ...bleReactiveWebApplicationContextTests.java | 3 +- .../AssertableWebApplicationContextTests.java | 3 +- .../platform/json/AbstractJsonTests.java | 13 +- .../tasks/bundling/BootZipCopyAction.java | 7 +- ...tiveImagePluginActionIntegrationTests.java | 7 +- .../nio/file/NestedFileSystemProvider.java | 1 + .../ModifiedClassPathClassLoader.java | 1 + ...AbstractReactiveWebServerFactoryTests.java | 11 +- .../AbstractServletWebServerFactoryTests.java | 10 +- 17 files changed, 146 insertions(+), 115 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraHealthContributorAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraHealthContributorAutoConfigurationTests.java index a76c786630f0..96b67e783580 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraHealthContributorAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraHealthContributorAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -54,6 +54,7 @@ void runWithCqlSessionOnlyShouldCreateDriverIndicator() { } @Test + @SuppressWarnings("resource") void runWithCqlSessionAndSpringDataAbsentShouldCreateDriverIndicator() { this.contextRunner.withBean(CqlSession.class, () -> mock(CqlSession.class)) .withClassLoader(new FilteredClassLoader("org.springframework.data")) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraReactiveHealthContributorAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraReactiveHealthContributorAutoConfigurationTests.java index 0f85369b4b3d..1a2ce0d87528 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraReactiveHealthContributorAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraReactiveHealthContributorAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -67,6 +67,7 @@ void runWithCqlSessionAndReactiveCassandraOperationsShouldCreateDriverIndicator( } @Test + @SuppressWarnings("resource") void runWithCqlSessionAndSpringDataAbsentShouldCreateDriverIndicator() { this.contextRunner.withBean(CqlSession.class, () -> mock(CqlSession.class)) .withClassLoader(new FilteredClassLoader("org.springframework.data")) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/zipkin/ZipkinConfigurationsSenderConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/zipkin/ZipkinConfigurationsSenderConfigurationTests.java index 7988fd310837..d5c2ddee7382 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/zipkin/ZipkinConfigurationsSenderConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/zipkin/ZipkinConfigurationsSenderConfigurationTests.java @@ -198,6 +198,7 @@ void shouldUseCustomHttpEndpointSupplierFactory() { } @Test + @SuppressWarnings("resource") void shouldUseCustomHttpEndpointSupplierFactoryWhenReactive() { this.reactiveContextRunner.withUserConfiguration(WebClientConfiguration.class) .withClassLoader(new FilteredClassLoader(URLConnectionSender.class)) @@ -207,6 +208,7 @@ void shouldUseCustomHttpEndpointSupplierFactoryWhenReactive() { } @Test + @SuppressWarnings("resource") void shouldUseCustomHttpEndpointSupplierFactoryWhenRestTemplate() { this.contextRunner.withUserConfiguration(RestTemplateConfiguration.class) .withClassLoader(new FilteredClassLoader(URLConnectionSender.class, WebClient.class)) diff --git a/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/AbstractDevToolsDataSourceAutoConfigurationTests.java b/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/AbstractDevToolsDataSourceAutoConfigurationTests.java index 76987fe76e68..a85d959247d1 100644 --- a/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/AbstractDevToolsDataSourceAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/AbstractDevToolsDataSourceAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -51,32 +51,35 @@ abstract class AbstractDevToolsDataSourceAutoConfigurationTests { @Test void singleManuallyConfiguredDataSourceIsNotClosed() throws Exception { - ConfigurableApplicationContext context = getContext(() -> createContext(SingleDataSourceConfiguration.class)); - DataSource dataSource = context.getBean(DataSource.class); - Statement statement = configureDataSourceBehavior(dataSource); - then(statement).should(never()).execute("SHUTDOWN"); + try (ConfigurableApplicationContext context = getContext( + () -> createContext(SingleDataSourceConfiguration.class))) { + DataSource dataSource = context.getBean(DataSource.class); + Statement statement = configureDataSourceBehavior(dataSource); + then(statement).should(never()).execute("SHUTDOWN"); + } } @Test void multipleDataSourcesAreIgnored() throws Exception { - ConfigurableApplicationContext context = getContext( - () -> createContext(MultipleDataSourcesConfiguration.class)); - Collection dataSources = context.getBeansOfType(DataSource.class).values(); - for (DataSource dataSource : dataSources) { - Statement statement = configureDataSourceBehavior(dataSource); - then(statement).should(never()).execute("SHUTDOWN"); + try (ConfigurableApplicationContext context = getContext( + () -> createContext(MultipleDataSourcesConfiguration.class))) { + Collection dataSources = context.getBeansOfType(DataSource.class).values(); + for (DataSource dataSource : dataSources) { + Statement statement = configureDataSourceBehavior(dataSource); + then(statement).should(never()).execute("SHUTDOWN"); + } } } @Test void emptyFactoryMethodMetadataIgnored() { - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - DataSource dataSource = mock(DataSource.class); - AnnotatedGenericBeanDefinition beanDefinition = new AnnotatedGenericBeanDefinition(dataSource.getClass()); - context.registerBeanDefinition("dataSource", beanDefinition); - context.register(DevToolsDataSourceAutoConfiguration.class); - context.refresh(); - context.close(); + try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) { + DataSource dataSource = mock(DataSource.class); + AnnotatedGenericBeanDefinition beanDefinition = new AnnotatedGenericBeanDefinition(dataSource.getClass()); + context.registerBeanDefinition("dataSource", beanDefinition); + context.register(DevToolsDataSourceAutoConfiguration.class); + context.refresh(); + } } protected final Statement configureDataSourceBehavior(DataSource dataSource) throws SQLException { diff --git a/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/DevToolsPooledDataSourceAutoConfigurationTests.java b/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/DevToolsPooledDataSourceAutoConfigurationTests.java index 5acc1ecd7aa0..a5cb76cd5de9 100644 --- a/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/DevToolsPooledDataSourceAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/DevToolsPooledDataSourceAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -61,88 +61,99 @@ void after() { @Test void autoConfiguredInMemoryDataSourceIsShutdown() throws Exception { - ConfigurableApplicationContext context = getContext( - () -> createContext(DataSourceAutoConfiguration.class, DataSourceSpyConfiguration.class)); - Statement statement = configureDataSourceBehavior(context.getBean(DataSource.class)); - context.close(); - then(statement).should().execute("SHUTDOWN"); + try (ConfigurableApplicationContext context = getContext( + () -> createContext(DataSourceAutoConfiguration.class, DataSourceSpyConfiguration.class))) { + Statement statement = configureDataSourceBehavior(context.getBean(DataSource.class)); + context.close(); + then(statement).should().execute("SHUTDOWN"); + } } @Test void autoConfiguredExternalDataSourceIsNotShutdown() throws Exception { - ConfigurableApplicationContext context = getContext(() -> createContext("org.postgresql.Driver", - DataSourceAutoConfiguration.class, DataSourceSpyConfiguration.class)); - Statement statement = configureDataSourceBehavior(context.getBean(DataSource.class)); - context.close(); - then(statement).should(never()).execute("SHUTDOWN"); + try (ConfigurableApplicationContext context = getContext(() -> createContext("org.postgresql.Driver", + DataSourceAutoConfiguration.class, DataSourceSpyConfiguration.class))) { + Statement statement = configureDataSourceBehavior(context.getBean(DataSource.class)); + context.close(); + then(statement).should(never()).execute("SHUTDOWN"); + } } @Test void h2ServerIsNotShutdown() throws Exception { - ConfigurableApplicationContext context = getContext(() -> createContext("org.h2.Driver", - "jdbc:h2:hsql://localhost", DataSourceAutoConfiguration.class, DataSourceSpyConfiguration.class)); - Statement statement = configureDataSourceBehavior(context.getBean(DataSource.class)); - context.close(); - then(statement).should(never()).execute("SHUTDOWN"); + try (ConfigurableApplicationContext context = getContext(() -> createContext("org.h2.Driver", + "jdbc:h2:hsql://localhost", DataSourceAutoConfiguration.class, DataSourceSpyConfiguration.class))) { + Statement statement = configureDataSourceBehavior(context.getBean(DataSource.class)); + context.close(); + then(statement).should(never()).execute("SHUTDOWN"); + } } @Test void inMemoryH2IsShutdown() throws Exception { - ConfigurableApplicationContext context = getContext(() -> createContext("org.h2.Driver", "jdbc:h2:mem:test", - DataSourceAutoConfiguration.class, DataSourceSpyConfiguration.class)); - Statement statement = configureDataSourceBehavior(context.getBean(DataSource.class)); - context.close(); - then(statement).should().execute("SHUTDOWN"); + try (ConfigurableApplicationContext context = getContext(() -> createContext("org.h2.Driver", + "jdbc:h2:mem:test", DataSourceAutoConfiguration.class, DataSourceSpyConfiguration.class))) { + Statement statement = configureDataSourceBehavior(context.getBean(DataSource.class)); + context.close(); + then(statement).should().execute("SHUTDOWN"); + } } @Test void hsqlServerIsNotShutdown() throws Exception { - ConfigurableApplicationContext context = getContext(() -> createContext("org.hsqldb.jdbcDriver", - "jdbc:hsqldb:hsql://localhost", DataSourceAutoConfiguration.class, DataSourceSpyConfiguration.class)); - Statement statement = configureDataSourceBehavior(context.getBean(DataSource.class)); - context.close(); - then(statement).should(never()).execute("SHUTDOWN"); + try (ConfigurableApplicationContext context = getContext(() -> createContext("org.hsqldb.jdbcDriver", + "jdbc:hsqldb:hsql://localhost", DataSourceAutoConfiguration.class, DataSourceSpyConfiguration.class))) { + Statement statement = configureDataSourceBehavior(context.getBean(DataSource.class)); + context.close(); + then(statement).should(never()).execute("SHUTDOWN"); + } } @Test void inMemoryHsqlIsShutdown() throws Exception { - ConfigurableApplicationContext context = getContext(() -> createContext("org.hsqldb.jdbcDriver", - "jdbc:hsqldb:mem:test", DataSourceAutoConfiguration.class, DataSourceSpyConfiguration.class)); - Statement statement = configureDataSourceBehavior(context.getBean(DataSource.class)); - context.close(); - then(statement).should().execute("SHUTDOWN"); + try (ConfigurableApplicationContext context = getContext(() -> createContext("org.hsqldb.jdbcDriver", + "jdbc:hsqldb:mem:test", DataSourceAutoConfiguration.class, DataSourceSpyConfiguration.class))) { + Statement statement = configureDataSourceBehavior(context.getBean(DataSource.class)); + context.close(); + then(statement).should().execute("SHUTDOWN"); + } } @Test void derbyClientIsNotShutdown() throws Exception { - ConfigurableApplicationContext context = getContext(() -> createContext("org.apache.derby.jdbc.ClientDriver", - "jdbc:derby://localhost", DataSourceAutoConfiguration.class, DataSourceSpyConfiguration.class)); - Statement statement = configureDataSourceBehavior(context.getBean(DataSource.class)); - context.close(); - then(statement).should(never()).execute("SHUTDOWN"); + try (ConfigurableApplicationContext context = getContext( + () -> createContext("org.apache.derby.jdbc.ClientDriver", "jdbc:derby://localhost", + DataSourceAutoConfiguration.class, DataSourceSpyConfiguration.class))) { + Statement statement = configureDataSourceBehavior(context.getBean(DataSource.class)); + context.close(); + then(statement).should(never()).execute("SHUTDOWN"); + } } @Test void inMemoryDerbyIsShutdown() throws Exception { - ConfigurableApplicationContext context = getContext( + try (ConfigurableApplicationContext context = getContext( () -> createContext("org.apache.derby.jdbc.EmbeddedDriver", "jdbc:derby:memory:test;create=true", - DataSourceAutoConfiguration.class, DataSourceSpyConfiguration.class)); - HikariDataSource dataSource = context.getBean(HikariDataSource.class); - JdbcTemplate jdbc = new JdbcTemplate(dataSource); - jdbc.execute("SELECT 1 FROM SYSIBM.SYSDUMMY1"); - HikariPoolMXBean pool = dataSource.getHikariPoolMXBean(); - // Prevent a race between Hikari's initialization and Derby shutdown - Awaitility.await() - .atMost(Duration.ofSeconds(30)) - .until(pool::getIdleConnections, (idle) -> idle == dataSource.getMinimumIdle()); - context.close(); - // Connect should fail as DB no longer exists - assertThatExceptionOfType(SQLException.class) - .isThrownBy(() -> new EmbeddedDriver().connect("jdbc:derby:memory:test", new Properties())) - .satisfies((ex) -> assertThat(ex.getSQLState()).isEqualTo("XJ004")); - // Shut Derby down fully so that it closes its log file - assertThatExceptionOfType(SQLException.class) - .isThrownBy(() -> new EmbeddedDriver().connect("jdbc:derby:;shutdown=true", new Properties())); + DataSourceAutoConfiguration.class, DataSourceSpyConfiguration.class))) { + HikariDataSource dataSource = context.getBean(HikariDataSource.class); + JdbcTemplate jdbc = new JdbcTemplate(dataSource); + jdbc.execute("SELECT 1 FROM SYSIBM.SYSDUMMY1"); + HikariPoolMXBean pool = dataSource.getHikariPoolMXBean(); + // Prevent a race between Hikari's initialization and Derby shutdown + Awaitility.await() + .atMost(Duration.ofSeconds(30)) + .until(pool::getIdleConnections, (idle) -> idle == dataSource.getMinimumIdle()); + context.close(); + // Connect should fail as DB no longer exists + assertThatExceptionOfType(SQLException.class).isThrownBy(() -> connect("jdbc:derby:memory:test")) + .satisfies((ex) -> assertThat(ex.getSQLState()).isEqualTo("XJ004")); + // Shut Derby down fully so that it closes its log file + assertThatExceptionOfType(SQLException.class).isThrownBy(() -> connect("jdbc:derby:;shutdown=true")); + } + } + + private void connect(String jdbcUrl) throws SQLException { + new EmbeddedDriver().connect(jdbcUrl, new Properties()).close(); } } diff --git a/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/DevToolsR2dbcAutoConfigurationTests.java b/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/DevToolsR2dbcAutoConfigurationTests.java index d06223ce7491..d5891df333f8 100644 --- a/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/DevToolsR2dbcAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/DevToolsR2dbcAutoConfigurationTests.java @@ -71,28 +71,32 @@ void autoConfiguredInMemoryConnectionFactoryIsShutdown() throws Exception { @Test void nonEmbeddedConnectionFactoryIsNotShutdown() throws Exception { - ConfigurableApplicationContext context = getContext(() -> createContext("r2dbc:h2:file:///testdb")); - ConnectionFactory connectionFactory = context.getBean(ConnectionFactory.class); - context.close(); - assertThat(shutdowns).doesNotContain(connectionFactory); + try (ConfigurableApplicationContext context = getContext(() -> createContext("r2dbc:h2:file:///testdb"))) { + ConnectionFactory connectionFactory = context.getBean(ConnectionFactory.class); + context.close(); + assertThat(shutdowns).doesNotContain(connectionFactory); + } } @Test void singleManuallyConfiguredConnectionFactoryIsNotClosed() throws Exception { - ConfigurableApplicationContext context = getContext( - () -> createContext(SingleConnectionFactoryConfiguration.class)); - ConnectionFactory connectionFactory = context.getBean(ConnectionFactory.class); - context.close(); - assertThat(shutdowns).doesNotContain(connectionFactory); + try (ConfigurableApplicationContext context = getContext( + () -> createContext(SingleConnectionFactoryConfiguration.class))) { + ConnectionFactory connectionFactory = context.getBean(ConnectionFactory.class); + context.close(); + assertThat(shutdowns).doesNotContain(connectionFactory); + } } @Test void multipleConnectionFactoriesAreIgnored() throws Exception { - ConfigurableApplicationContext context = getContext( - () -> createContext(MultipleConnectionFactoriesConfiguration.class)); - Collection connectionFactory = context.getBeansOfType(ConnectionFactory.class).values(); - context.close(); - assertThat(shutdowns).doesNotContainAnyElementsOf(connectionFactory); + try (ConfigurableApplicationContext context = getContext( + () -> createContext(MultipleConnectionFactoriesConfiguration.class))) { + Collection connectionFactory = context.getBeansOfType(ConnectionFactory.class) + .values(); + context.close(); + assertThat(shutdowns).doesNotContainAnyElementsOf(connectionFactory); + } } @Test diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/AbstractApplicationContextRunner.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/AbstractApplicationContextRunner.java index 635222f8c749..8ea584c79cac 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/AbstractApplicationContextRunner.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/AbstractApplicationContextRunner.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -381,7 +381,7 @@ private void withContextClassLoader(ClassLoader classLoader, Runnable action) { } } - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "resource" }) private A createAssertableContext(boolean refresh) { ResolvableType resolvableType = ResolvableType.forClass(AbstractApplicationContextRunner.class, getClass()); Class assertType = (Class) resolvableType.resolveGeneric(1); diff --git a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/assertj/AssertableApplicationContextTests.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/assertj/AssertableApplicationContextTests.java index 91189ce2a99c..5a1a81b2d649 100644 --- a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/assertj/AssertableApplicationContextTests.java +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/assertj/AssertableApplicationContextTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -32,6 +32,7 @@ class AssertableApplicationContextTests { @Test + @SuppressWarnings("resource") void getShouldReturnProxy() { AssertableApplicationContext context = AssertableApplicationContext .get(() -> mock(ConfigurableApplicationContext.class)); diff --git a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/assertj/AssertableReactiveWebApplicationContextTests.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/assertj/AssertableReactiveWebApplicationContextTests.java index b84b776bbd35..faa827c69c7e 100644 --- a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/assertj/AssertableReactiveWebApplicationContextTests.java +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/assertj/AssertableReactiveWebApplicationContextTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -32,6 +32,7 @@ class AssertableReactiveWebApplicationContextTests { @Test + @SuppressWarnings("resource") void getShouldReturnProxy() { AssertableReactiveWebApplicationContext context = AssertableReactiveWebApplicationContext .get(() -> mock(ConfigurableReactiveWebApplicationContext.class)); diff --git a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/assertj/AssertableWebApplicationContextTests.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/assertj/AssertableWebApplicationContextTests.java index 53873f9c47ad..980012c4a079 100644 --- a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/assertj/AssertableWebApplicationContextTests.java +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/assertj/AssertableWebApplicationContextTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -32,6 +32,7 @@ class AssertableWebApplicationContextTests { @Test + @SuppressWarnings("resource") void getShouldReturnProxy() { AssertableWebApplicationContext context = AssertableWebApplicationContext .get(() -> mock(ConfigurableWebApplicationContext.class)); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/json/AbstractJsonTests.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/json/AbstractJsonTests.java index edc27b55541b..3d86534cf91b 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/json/AbstractJsonTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/json/AbstractJsonTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -17,8 +17,10 @@ package org.springframework.boot.buildpack.platform.json; import java.io.BufferedReader; +import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.io.UncheckedIOException; import java.nio.charset.StandardCharsets; import java.util.stream.Collectors; @@ -45,8 +47,13 @@ protected final InputStream getContent(String name) { } protected final String getContentAsString(String name) { - return new BufferedReader(new InputStreamReader(getContent(name), StandardCharsets.UTF_8)).lines() - .collect(Collectors.joining("\n")); + try (InputStream in = getContent(name)) { + return new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)).lines() + .collect(Collectors.joining("\n")); + } + catch (IOException ex) { + throw new UncheckedIOException(ex); + } } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootZipCopyAction.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootZipCopyAction.java index fdde482b7e2c..a4870eeb31bd 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootZipCopyAction.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootZipCopyAction.java @@ -348,8 +348,11 @@ private void writeJarToolsIfNecessary() throws IOException { private void writeJarModeLibrary(String location, JarModeLibrary library) throws IOException { String name = location + library.getName(); - writeEntry(name, ZipEntryContentWriter.fromInputStream(library.openStream()), false, - (entry) -> prepareStoredEntry(library.openStream(), entry)); + writeEntry(name, ZipEntryContentWriter.fromInputStream(library.openStream()), false, (entry) -> { + try (InputStream in = library.openStream()) { + prepareStoredEntry(library.openStream(), entry); + } + }); if (BootZipCopyAction.this.layerResolver != null) { Layer layer = BootZipCopyAction.this.layerResolver.getLayer(library); this.layerIndex.add(layer, name); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/NativeImagePluginActionIntegrationTests.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/NativeImagePluginActionIntegrationTests.java index c711b77e58e4..43ff5357c591 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/NativeImagePluginActionIntegrationTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/NativeImagePluginActionIntegrationTests.java @@ -130,9 +130,10 @@ void nativeEntryIsAddedToManifest() throws IOException { BuildResult result = this.gradleBuild.build("bootJar"); assertThat(result.task(":bootJar").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); File buildLibs = new File(this.gradleBuild.getProjectDir(), "build/libs"); - JarFile jarFile = new JarFile(new File(buildLibs, this.gradleBuild.getProjectDir().getName() + ".jar")); - Manifest manifest = jarFile.getManifest(); - assertThat(manifest.getMainAttributes().getValue("Spring-Boot-Native-Processed")).isEqualTo("true"); + try (JarFile jarFile = new JarFile(new File(buildLibs, this.gradleBuild.getProjectDir().getName() + ".jar"))) { + Manifest manifest = jarFile.getManifest(); + assertThat(manifest.getMainAttributes().getValue("Spring-Boot-Native-Processed")).isEqualTo("true"); + } } private String projectPath(String path) { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/nio/file/NestedFileSystemProvider.java b/spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/nio/file/NestedFileSystemProvider.java index fce7e8c56580..133b86ff29de 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/nio/file/NestedFileSystemProvider.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/nio/file/NestedFileSystemProvider.java @@ -84,6 +84,7 @@ public FileSystem getFileSystem(URI uri) { } @Override + @SuppressWarnings("resource") public Path getPath(URI uri) { NestedLocation location = NestedLocation.fromUri(uri); synchronized (this.fileSystems) { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/classpath/ModifiedClassPathClassLoader.java b/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/classpath/ModifiedClassPathClassLoader.java index 8b014b928533..07065ba859c9 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/classpath/ModifiedClassPathClassLoader.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/classpath/ModifiedClassPathClassLoader.java @@ -99,6 +99,7 @@ public Class loadClass(String name) throws ClassNotFoundException { return super.loadClass(name); } + @SuppressWarnings("resource") static ModifiedClassPathClassLoader get(Class testClass, Method testMethod, List arguments) { Set candidates = new LinkedHashSet<>(); candidates.add(testClass); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java index 116e21e01f71..c1d20a9be109 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java @@ -569,19 +569,16 @@ protected void whenHttp2IsEnabledAndSslIsDisabledThenH2cCanBeUsed() throws Excep factory.setHttp2(http2); this.webServer = factory.getWebServer(new EchoHandler()); this.webServer.start(); - org.eclipse.jetty.client.HttpClient client = new org.eclipse.jetty.client.HttpClient( - new HttpClientTransportOverHTTP2(new HTTP2Client())); - client.start(); - try { + + try (org.eclipse.jetty.client.HttpClient client = new org.eclipse.jetty.client.HttpClient( + new HttpClientTransportOverHTTP2(new HTTP2Client()))) { + client.start(); ContentResponse response = client.POST("http://localhost:" + this.webServer.getPort()) .body(new StringRequestContent("text/plain", "Hello World")) .send(); assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value()); assertThat(response.getContentAsString()).isEqualTo("Hello World"); } - finally { - client.stop(); - } } @Test diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/server/AbstractServletWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/server/AbstractServletWebServerFactoryTests.java index 9219de35c0fb..bafcd060dc88 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/server/AbstractServletWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/server/AbstractServletWebServerFactoryTests.java @@ -1291,17 +1291,13 @@ protected void whenHttp2IsEnabledAndSslIsDisabledThenH2cCanBeUsed() throws Excep factory.setHttp2(http2); this.webServer = factory.getWebServer(exampleServletRegistration()); this.webServer.start(); - org.eclipse.jetty.client.HttpClient client = new org.eclipse.jetty.client.HttpClient( - new HttpClientTransportOverHTTP2(new HTTP2Client())); - client.start(); - try { + try (org.eclipse.jetty.client.HttpClient client = new org.eclipse.jetty.client.HttpClient( + new HttpClientTransportOverHTTP2(new HTTP2Client()))) { + client.start(); ContentResponse response = client.GET("http://localhost:" + this.webServer.getPort() + "/hello"); assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value()); assertThat(response.getContentAsString()).isEqualTo("Hello World"); } - finally { - client.stop(); - } } @Test From d924e4d9998945933a4a9947a6ca776e303db1ea Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 26 Nov 2024 13:42:03 +0000 Subject: [PATCH 010/203] Mark shaded application's jar as multi-release by default Spring Framework now uses a multi-release jar for its virtual thread support. If the shaded jar is not marked as being a multi-release jar and virtual threads are enabled, the application will fail to start as the Java 21+ virtual threads delegate will be unavailable. This commit updates the starter parent's default configuration for the Maven Shade plugin to set Multi-Release: true in the application's manifest. Closes gh-43284 --- .../spring-boot-starter-parent/build.gradle | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-parent/build.gradle b/spring-boot-project/spring-boot-starters/spring-boot-starter-parent/build.gradle index 4c85421b1404..6c4c81d4c4f0 100644 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-parent/build.gradle +++ b/spring-boot-project/spring-boot-starters/spring-boot-starter-parent/build.gradle @@ -234,7 +234,10 @@ publishing.publications.withType(MavenPublication) { } transformer(implementation: 'org.apache.maven.plugins.shade.resource.ServicesResourceTransformer') transformer(implementation: 'org.apache.maven.plugins.shade.resource.ManifestResourceTransformer') { - delegate.mainClass('${start-class}') + manifestEntries { + delegate.'Main-Class'('${start-class}') + delegate.'Multi-Release'('true') + } } } } From 1c64a40b921b8ab54161e4e1167e17481fe4f5c7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Nov 2024 19:18:55 +0000 Subject: [PATCH 011/203] Bump spring-io/artifactory-deploy-action from 0.0.1 to 0.0.2 Bumps [spring-io/artifactory-deploy-action](https://github.com/spring-io/artifactory-deploy-action) from 0.0.1 to 0.0.2. - [Release notes](https://github.com/spring-io/artifactory-deploy-action/releases) - [Commits](https://github.com/spring-io/artifactory-deploy-action/compare/26bbe925a75f4f863e1e529e85be2d0093cac116...dc1913008c0599f0c4b1fdafb6ff3c502b3565ea) --- updated-dependencies: - dependency-name: spring-io/artifactory-deploy-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] See gh-43285 --- .github/workflows/build-and-deploy-snapshot.yml | 2 +- .github/workflows/release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-deploy-snapshot.yml b/.github/workflows/build-and-deploy-snapshot.yml index 406bae370220..cdfa34076ffb 100644 --- a/.github/workflows/build-and-deploy-snapshot.yml +++ b/.github/workflows/build-and-deploy-snapshot.yml @@ -25,7 +25,7 @@ jobs: gradle-cache-read-only: false publish: true - name: Deploy - uses: spring-io/artifactory-deploy-action@26bbe925a75f4f863e1e529e85be2d0093cac116 # v0.0.1 + uses: spring-io/artifactory-deploy-action@dc1913008c0599f0c4b1fdafb6ff3c502b3565ea # v0.0.2 with: build-name: ${{ vars.COMMERCIAL && format('spring-boot-commercial-{0}', github.ref_name) || format('spring-boot-{0}', github.ref_name) }} folder: 'deployment-repository' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index de84836325df..20cd4c5d0c7b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -25,7 +25,7 @@ jobs: gradle-cache-read-only: false publish: true - name: Stage Release - uses: spring-io/artifactory-deploy-action@26bbe925a75f4f863e1e529e85be2d0093cac116 # v0.0.1 + uses: spring-io/artifactory-deploy-action@dc1913008c0599f0c4b1fdafb6ff3c502b3565ea # v0.0.2 with: build-name: ${{ vars.COMMERCIAL && format('spring-boot-commercial-{0}', steps.build-and-publish.outputs.version) || format('spring-boot-{0}', steps.build-and-publish.outputs.version) }} folder: 'deployment-repository' From d8c41c2583bf5b5c17bf281715c5ae856a0e6ef6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Tue, 26 Nov 2024 19:56:32 +0100 Subject: [PATCH 012/203] Defensively unwrap CacheConnectionFactory This commit refines the optimization introduced in gh-39816 to only unwrap our own caching connection factory. The more advanced unwrap algorithm is still available, but opt-in only. Unwrapping more aggressively may break use cases where the wrapped ConnectionFactory is required, i.e. for transactional purposes. Closes gh-43277 --- .../jms/JmsAnnotationDrivenConfiguration.java | 2 +- .../reference/pages/messaging/jms.adoc | 2 + .../MyJmsConfiguration.java | 2 +- .../receiving/custom/MyJmsConfiguration.java | 2 +- .../MyJmsConfiguration.kt | 2 +- .../receiving/custom/MyJmsConfiguration.kt | 2 +- .../boot/jms/ConnectionFactoryUnwrapper.java | 17 +++ .../jms/ConnectionFactoryUnwrapperTests.java | 144 ++++++++++++------ 8 files changed, 122 insertions(+), 51 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/JmsAnnotationDrivenConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/JmsAnnotationDrivenConfiguration.java index 6de5bc8fcf04..cea5d85401d4 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/JmsAnnotationDrivenConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/JmsAnnotationDrivenConfiguration.java @@ -90,7 +90,7 @@ DefaultJmsListenerContainerFactoryConfigurer jmsListenerContainerFactoryConfigur DefaultJmsListenerContainerFactory jmsListenerContainerFactory( DefaultJmsListenerContainerFactoryConfigurer configurer, ConnectionFactory connectionFactory) { DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory(); - configurer.configure(factory, ConnectionFactoryUnwrapper.unwrap(connectionFactory)); + configurer.configure(factory, ConnectionFactoryUnwrapper.unwrapCaching(connectionFactory)); return factory; } diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/messaging/jms.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/messaging/jms.adoc index 78d985c9687d..52cc56b34e61 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/messaging/jms.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/messaging/jms.adoc @@ -165,6 +165,8 @@ In most scenarios, message listener containers should be configured against the This way each listener container has its own connection and this gives full responsibility to it in terms of local recovery. The auto-configuration uses javadoc:org.springframework.boot.jms.ConnectionFactoryUnwrapper[] to unwrap the native connection factory from the auto-configured one. +NOTE: The auto-configuration only unwraps `CachedConnectionFactory`. + By default, the default factory is transactional. If you run in an infrastructure where a javadoc:org.springframework.transaction.jta.JtaTransactionManager[] is present, it is associated to the listener container by default. If not, the `sessionTransacted` flag is enabled. diff --git a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/messaging/disabletransactedjmssession/MyJmsConfiguration.java b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/messaging/disabletransactedjmssession/MyJmsConfiguration.java index cedf98bea604..c033190a73b0 100644 --- a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/messaging/disabletransactedjmssession/MyJmsConfiguration.java +++ b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/messaging/disabletransactedjmssession/MyJmsConfiguration.java @@ -31,7 +31,7 @@ public class MyJmsConfiguration { public DefaultJmsListenerContainerFactory jmsListenerContainerFactory(ConnectionFactory connectionFactory, DefaultJmsListenerContainerFactoryConfigurer configurer) { DefaultJmsListenerContainerFactory listenerFactory = new DefaultJmsListenerContainerFactory(); - configurer.configure(listenerFactory, ConnectionFactoryUnwrapper.unwrap(connectionFactory)); + configurer.configure(listenerFactory, ConnectionFactoryUnwrapper.unwrapCaching(connectionFactory)); listenerFactory.setTransactionManager(null); listenerFactory.setSessionTransacted(false); return listenerFactory; diff --git a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/messaging/jms/receiving/custom/MyJmsConfiguration.java b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/messaging/jms/receiving/custom/MyJmsConfiguration.java index ac9b38cde542..7261056cb242 100644 --- a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/messaging/jms/receiving/custom/MyJmsConfiguration.java +++ b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/messaging/jms/receiving/custom/MyJmsConfiguration.java @@ -31,7 +31,7 @@ public class MyJmsConfiguration { public DefaultJmsListenerContainerFactory myFactory(DefaultJmsListenerContainerFactoryConfigurer configurer, ConnectionFactory connectionFactory) { DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory(); - configurer.configure(factory, ConnectionFactoryUnwrapper.unwrap(connectionFactory)); + configurer.configure(factory, ConnectionFactoryUnwrapper.unwrapCaching(connectionFactory)); factory.setMessageConverter(new MyMessageConverter()); return factory; } diff --git a/spring-boot-project/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/messaging/disabletransactedjmssession/MyJmsConfiguration.kt b/spring-boot-project/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/messaging/disabletransactedjmssession/MyJmsConfiguration.kt index 39b2f194448a..d1ee891f790f 100644 --- a/spring-boot-project/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/messaging/disabletransactedjmssession/MyJmsConfiguration.kt +++ b/spring-boot-project/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/messaging/disabletransactedjmssession/MyJmsConfiguration.kt @@ -31,7 +31,7 @@ class MyJmsConfiguration { fun jmsListenerContainerFactory(connectionFactory: ConnectionFactory?, configurer: DefaultJmsListenerContainerFactoryConfigurer): DefaultJmsListenerContainerFactory { val listenerFactory = DefaultJmsListenerContainerFactory() - configurer.configure(listenerFactory, ConnectionFactoryUnwrapper.unwrap(connectionFactory)) + configurer.configure(listenerFactory, ConnectionFactoryUnwrapper.unwrapCaching(connectionFactory)) listenerFactory.setTransactionManager(null) listenerFactory.setSessionTransacted(false) return listenerFactory diff --git a/spring-boot-project/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/messaging/jms/receiving/custom/MyJmsConfiguration.kt b/spring-boot-project/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/messaging/jms/receiving/custom/MyJmsConfiguration.kt index d788b97d998a..6228ceea130c 100644 --- a/spring-boot-project/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/messaging/jms/receiving/custom/MyJmsConfiguration.kt +++ b/spring-boot-project/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/messaging/jms/receiving/custom/MyJmsConfiguration.kt @@ -30,7 +30,7 @@ class MyJmsConfiguration { fun myFactory(configurer: DefaultJmsListenerContainerFactoryConfigurer, connectionFactory: ConnectionFactory): DefaultJmsListenerContainerFactory { val factory = DefaultJmsListenerContainerFactory() - configurer.configure(factory, ConnectionFactoryUnwrapper.unwrap(connectionFactory)) + configurer.configure(factory, ConnectionFactoryUnwrapper.unwrapCaching(connectionFactory)) factory.setMessageConverter(MyMessageConverter()) return factory } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jms/ConnectionFactoryUnwrapper.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jms/ConnectionFactoryUnwrapper.java index 681d70e5325a..ec98a93b21e9 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jms/ConnectionFactoryUnwrapper.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jms/ConnectionFactoryUnwrapper.java @@ -33,6 +33,23 @@ public final class ConnectionFactoryUnwrapper { private ConnectionFactoryUnwrapper() { } + /** + * Return the native {@link ConnectionFactory} by unwrapping ot from a + * {@link CachingConnectionFactory}. Return the given {@link ConnectionFactory} if no + * {@link CachingConnectionFactory} wrapper has been detected. + * @param connectionFactory a connection factory + * @return the native connection factory that a {@link CachingConnectionFactory} + * wraps, if any + * @since 3.4.1 + */ + public static ConnectionFactory unwrapCaching(ConnectionFactory connectionFactory) { + if (connectionFactory instanceof CachingConnectionFactory cachingConnectionFactory) { + ConnectionFactory unwrapedConnectionFactory = cachingConnectionFactory.getTargetConnectionFactory(); + return (unwrapedConnectionFactory != null) ? unwrapCaching(unwrapedConnectionFactory) : connectionFactory; + } + return connectionFactory; + } + /** * Return the native {@link ConnectionFactory} by unwrapping it from a cache or pool * connection factory. Return the given {@link ConnectionFactory} if no caching diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jms/ConnectionFactoryUnwrapperTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jms/ConnectionFactoryUnwrapperTests.java index 993860a2accf..5a65cfde8f79 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jms/ConnectionFactoryUnwrapperTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jms/ConnectionFactoryUnwrapperTests.java @@ -17,6 +17,7 @@ package org.springframework.boot.jms; import jakarta.jms.ConnectionFactory; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.messaginghub.pooled.jms.JmsPoolConnectionFactory; @@ -35,59 +36,110 @@ */ class ConnectionFactoryUnwrapperTests { - @Test - void unwrapWithSingleConnectionFactory() { - ConnectionFactory connectionFactory = new SingleConnectionFactory(); - assertThat(ConnectionFactoryUnwrapper.unwrap(connectionFactory)).isSameAs(connectionFactory); - } + @Nested + class UnwrapCaching { - @Test - void unwrapWithConnectionFactory() { - ConnectionFactory connectionFactory = mock(ConnectionFactory.class); - assertThat(ConnectionFactoryUnwrapper.unwrap(connectionFactory)).isSameAs(connectionFactory); - } + @Test + void unwrapWithSingleConnectionFactory() { + ConnectionFactory connectionFactory = new SingleConnectionFactory(); + assertThat(unwrapCaching(connectionFactory)).isSameAs(connectionFactory); + } - @Test - void unwrapWithCachingConnectionFactory() { - ConnectionFactory connectionFactory = mock(ConnectionFactory.class); - assertThat(ConnectionFactoryUnwrapper.unwrap(new CachingConnectionFactory(connectionFactory))) - .isSameAs(connectionFactory); - } + @Test + void unwrapWithConnectionFactory() { + ConnectionFactory connectionFactory = mock(ConnectionFactory.class); + assertThat(unwrapCaching(connectionFactory)).isSameAs(connectionFactory); + } - @Test - void unwrapWithNestedCachingConnectionFactories() { - ConnectionFactory connectionFactory = mock(ConnectionFactory.class); - CachingConnectionFactory firstCachingConnectionFactory = new CachingConnectionFactory(connectionFactory); - CachingConnectionFactory secondCachingConnectionFactory = new CachingConnectionFactory( - firstCachingConnectionFactory); - assertThat(ConnectionFactoryUnwrapper.unwrap(secondCachingConnectionFactory)).isSameAs(connectionFactory); - } + @Test + void unwrapWithCachingConnectionFactory() { + ConnectionFactory connectionFactory = mock(ConnectionFactory.class); + assertThat(unwrapCaching(new CachingConnectionFactory(connectionFactory))).isSameAs(connectionFactory); + } - @Test - void unwrapWithJmsPoolConnectionFactory() { - ConnectionFactory connectionFactory = mock(ConnectionFactory.class); - JmsPoolConnectionFactory poolConnectionFactory = new JmsPoolConnectionFactory(); - poolConnectionFactory.setConnectionFactory(connectionFactory); - assertThat(ConnectionFactoryUnwrapper.unwrap(poolConnectionFactory)).isSameAs(connectionFactory); - } + @Test + void unwrapWithNestedCachingConnectionFactories() { + ConnectionFactory connectionFactory = mock(ConnectionFactory.class); + CachingConnectionFactory firstCachingConnectionFactory = new CachingConnectionFactory(connectionFactory); + CachingConnectionFactory secondCachingConnectionFactory = new CachingConnectionFactory( + firstCachingConnectionFactory); + assertThat(unwrapCaching(secondCachingConnectionFactory)).isSameAs(connectionFactory); + } + + @Test + void unwrapWithJmsPoolConnectionFactory() { + ConnectionFactory connectionFactory = mock(ConnectionFactory.class); + JmsPoolConnectionFactory poolConnectionFactory = new JmsPoolConnectionFactory(); + poolConnectionFactory.setConnectionFactory(connectionFactory); + assertThat(unwrapCaching(poolConnectionFactory)).isSameAs(poolConnectionFactory); + } + + private ConnectionFactory unwrapCaching(ConnectionFactory connectionFactory) { + return ConnectionFactoryUnwrapper.unwrapCaching(connectionFactory); + } - @Test - void unwrapWithNestedJmsPoolConnectionFactories() { - ConnectionFactory connectionFactory = mock(ConnectionFactory.class); - JmsPoolConnectionFactory firstPooledConnectionFactory = new JmsPoolConnectionFactory(); - firstPooledConnectionFactory.setConnectionFactory(connectionFactory); - JmsPoolConnectionFactory secondPooledConnectionFactory = new JmsPoolConnectionFactory(); - secondPooledConnectionFactory.setConnectionFactory(firstPooledConnectionFactory); - assertThat(ConnectionFactoryUnwrapper.unwrap(secondPooledConnectionFactory)).isSameAs(connectionFactory); } - @Test - @ClassPathExclusions("pooled-jms-*") - void unwrapWithoutJmsPoolOnClasspath() { - assertThat(ClassUtils.isPresent("org.messaginghub.pooled.jms.JmsPoolConnectionFactory", null)).isFalse(); - ConnectionFactory connectionFactory = mock(ConnectionFactory.class); - assertThat(ConnectionFactoryUnwrapper.unwrap(new CachingConnectionFactory(connectionFactory))) - .isSameAs(connectionFactory); + @Nested + class Unwrap { + + @Test + void unwrapWithSingleConnectionFactory() { + ConnectionFactory connectionFactory = new SingleConnectionFactory(); + assertThat(unwrap(connectionFactory)).isSameAs(connectionFactory); + } + + @Test + void unwrapWithConnectionFactory() { + ConnectionFactory connectionFactory = mock(ConnectionFactory.class); + assertThat(unwrap(connectionFactory)).isSameAs(connectionFactory); + } + + @Test + void unwrapWithCachingConnectionFactory() { + ConnectionFactory connectionFactory = mock(ConnectionFactory.class); + assertThat(unwrap(new CachingConnectionFactory(connectionFactory))).isSameAs(connectionFactory); + } + + @Test + void unwrapWithNestedCachingConnectionFactories() { + ConnectionFactory connectionFactory = mock(ConnectionFactory.class); + CachingConnectionFactory firstCachingConnectionFactory = new CachingConnectionFactory(connectionFactory); + CachingConnectionFactory secondCachingConnectionFactory = new CachingConnectionFactory( + firstCachingConnectionFactory); + assertThat(unwrap(secondCachingConnectionFactory)).isSameAs(connectionFactory); + } + + @Test + void unwrapWithJmsPoolConnectionFactory() { + ConnectionFactory connectionFactory = mock(ConnectionFactory.class); + JmsPoolConnectionFactory poolConnectionFactory = new JmsPoolConnectionFactory(); + poolConnectionFactory.setConnectionFactory(connectionFactory); + assertThat(unwrap(poolConnectionFactory)).isSameAs(connectionFactory); + } + + @Test + void unwrapWithNestedJmsPoolConnectionFactories() { + ConnectionFactory connectionFactory = mock(ConnectionFactory.class); + JmsPoolConnectionFactory firstPooledConnectionFactory = new JmsPoolConnectionFactory(); + firstPooledConnectionFactory.setConnectionFactory(connectionFactory); + JmsPoolConnectionFactory secondPooledConnectionFactory = new JmsPoolConnectionFactory(); + secondPooledConnectionFactory.setConnectionFactory(firstPooledConnectionFactory); + assertThat(unwrap(secondPooledConnectionFactory)).isSameAs(connectionFactory); + } + + @Test + @ClassPathExclusions("pooled-jms-*") + void unwrapWithoutJmsPoolOnClasspath() { + assertThat(ClassUtils.isPresent("org.messaginghub.pooled.jms.JmsPoolConnectionFactory", null)).isFalse(); + ConnectionFactory connectionFactory = mock(ConnectionFactory.class); + assertThat(unwrap(new CachingConnectionFactory(connectionFactory))).isSameAs(connectionFactory); + } + + private ConnectionFactory unwrap(ConnectionFactory connectionFactory) { + return ConnectionFactoryUnwrapper.unwrap(connectionFactory); + } + } } From 16838a9b58c1f940498ec513ecb78a7a54dbc642 Mon Sep 17 00:00:00 2001 From: Tran Ngoc Nhan Date: Sat, 23 Nov 2024 00:47:13 +0700 Subject: [PATCH 013/203] Fix syntax in reference guide See gh-43271 --- .../modules/how-to/pages/properties-and-configuration.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/how-to/pages/properties-and-configuration.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/how-to/pages/properties-and-configuration.adoc index 010239611594..e5d5be207507 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/how-to/pages/properties-and-configuration.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/how-to/pages/properties-and-configuration.adoc @@ -209,7 +209,7 @@ spring.datasource.url=jdbc:mysql://localhost/test server.port=9000 ---- -See xref:reference:features/external-config.adoc#features.external-config.yaml[] in the "`Spring Boot Features'" section for more information about YAML. +See xref:reference:features/external-config.adoc#features.external-config.yaml[] in the "`Spring Boot Features`" section for more information about YAML. From 7bc709c32fdbf2ba02e2dca63597567c4bcacecc Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 27 Nov 2024 19:30:58 +0000 Subject: [PATCH 014/203] Fix subName from adapted name with value processor Previously, when a configuration property name was created by adapting a source with a value processor, creating sub names from that property name did not work correctly. This broke binding of prefixed environment variables to a map as the ancestor checking did not work. Fixes gh-43304 --- .../source/ConfigurationPropertyName.java | 10 +++++----- .../source/ConfigurationPropertyNameTests.java | 18 +++++++++++++++++- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertyName.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertyName.java index 91052105ff3a..bd1e7f1dda00 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertyName.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertyName.java @@ -773,7 +773,7 @@ Elements append(Elements additional) { ElementType[] type = new ElementType[size]; System.arraycopy(this.type, 0, type, 0, this.size); System.arraycopy(additional.type, 0, type, this.size, additional.size); - CharSequence[] resolved = newResolved(size); + CharSequence[] resolved = newResolved(0, size); for (int i = 0; i < additional.size; i++) { resolved[this.size + i] = additional.get(i); } @@ -781,13 +781,13 @@ Elements append(Elements additional) { } Elements chop(int size) { - CharSequence[] resolved = newResolved(size); + CharSequence[] resolved = newResolved(0, size); return new Elements(this.source, size, this.start, this.end, this.type, resolved); } Elements subElements(int offset) { int size = this.size - offset; - CharSequence[] resolved = newResolved(size); + CharSequence[] resolved = newResolved(offset, size); int[] start = new int[size]; System.arraycopy(this.start, offset, start, 0, size); int[] end = new int[size]; @@ -797,10 +797,10 @@ Elements subElements(int offset) { return new Elements(this.source, size, start, end, type, resolved); } - private CharSequence[] newResolved(int size) { + private CharSequence[] newResolved(int offset, int size) { CharSequence[] resolved = new CharSequence[size]; if (this.resolved != null) { - System.arraycopy(this.resolved, 0, resolved, 0, Math.min(size, this.size)); + System.arraycopy(this.resolved, offset, resolved, 0, Math.min(size, this.size)); } return resolved; } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertyNameTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertyNameTests.java index b33d9c3ae398..707e4468670d 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertyNameTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertyNameTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -19,6 +19,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Locale; import org.junit.jupiter.api.Test; @@ -492,6 +493,21 @@ void subNameWhenOffsetLessThanSizeShouldReturnSubName() { assertThat(name.subName(2)).hasToString("baz"); } + @Test + void subNameOfAdaptedNameWhenOffsetLessThanSizeShouldReturnSubName() { + ConfigurationPropertyName name = ConfigurationPropertyName.adapt("MY_LOGGING_LEVEL_ONE", '_'); + assertThat(name.subName(1)).hasToString("logging.level.one"); + assertThat(name.subName(2)).hasToString("level.one"); + } + + @Test + void subNameOfAdaptedNameWithValueProcessorWhenOffsetLessThanSizeShouldReturnSubName() { + ConfigurationPropertyName name = ConfigurationPropertyName.adapt("MY_LOGGING_LEVEL_ONE", '_', + (value) -> value.toString().toLowerCase(Locale.ENGLISH)); + assertThat(name.subName(1)).hasToString("logging.level.one"); + assertThat(name.subName(2)).hasToString("level.one"); + } + @Test void subNameWhenOffsetZeroShouldReturnName() { ConfigurationPropertyName name = ConfigurationPropertyName.of("foo.bar.baz"); From 57a5fa0555b961812af523f5db0ecb9906a25a51 Mon Sep 17 00:00:00 2001 From: Tran Ngoc Nhan Date: Wed, 27 Nov 2024 19:18:19 +0700 Subject: [PATCH 015/203] Fix Javadoc link for Hikari See gh-43305 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 58d09ce809e2..51c60d3505f4 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -561,7 +561,7 @@ bom { } links { site("https://github.com/brettwooldridge/HikariCP") - javadoc("https://javadoc.io/doc/com.zaxxer/HikariCP/{version}", "com.zaxxer.hikari") + javadoc("https://javadoc.io/doc/com.zaxxer/HikariCP/{version}/com.zaxxer.hikari", "com.zaxxer.hikari") } } library("HSQLDB", "2.7.3") { From a1c1e32947b6240a70ada8aac7909d3eecffa864 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 28 Nov 2024 11:04:50 +0000 Subject: [PATCH 016/203] Call spring.factories customizers in the same way as one from props Previously, customizers loaded from spring.factories were called using LambdaSafe. This resulted in customizers with a generic type more specific than Object being ignored. A customizer loaded from the logging.structured.json.customizer property was not affected as it was called directly rather than through LambdaSafe. This commit aligns the way in which customizers loaded from spring.factories are called with the way in which any customizer specified using the logging.structured.json.customizer property is called. Closes gh-43312 --- .../StructuredLogFormatterFactory.java | 8 ++-- .../StructuredLogFormatterFactoryTests.java | 46 ++++++++++++++++--- 2 files changed, 43 insertions(+), 11 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/structured/StructuredLogFormatterFactory.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/structured/StructuredLogFormatterFactory.java index e5fc4c3218d2..22e3c6d872c0 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/structured/StructuredLogFormatterFactory.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/structured/StructuredLogFormatterFactory.java @@ -27,7 +27,6 @@ import org.springframework.boot.util.Instantiator; import org.springframework.boot.util.Instantiator.AvailableParameters; import org.springframework.boot.util.Instantiator.FailureHandler; -import org.springframework.boot.util.LambdaSafe; import org.springframework.core.GenericTypeResolver; import org.springframework.core.env.Environment; import org.springframework.core.io.support.SpringFactoriesLoader; @@ -108,11 +107,12 @@ private List> loadStructuredLoggingJso ArgumentResolver.from(this.instantiator::getArg)); } - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) private void invokeCustomizers(List> customizers, Members members) { - LambdaSafe.callbacks(StructuredLoggingJsonMembersCustomizer.class, customizers, members) - .invoke((customizer) -> customizer.customize(members)); + for (StructuredLoggingJsonMembersCustomizer customizer : customizers) { + ((StructuredLoggingJsonMembersCustomizer) customizer).customize(members); + } } /** diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/structured/StructuredLogFormatterFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/structured/StructuredLogFormatterFactoryTests.java index c91a75f0acd3..cc0bbc8d0433 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/structured/StructuredLogFormatterFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/structured/StructuredLogFormatterFactoryTests.java @@ -20,6 +20,7 @@ import org.junit.jupiter.api.Test; +import org.springframework.boot.json.JsonWriter.Members; import org.springframework.boot.json.JsonWriter.ValueProcessor; import org.springframework.boot.logging.structured.StructuredLogFormatterFactory.CommonFormatters; import org.springframework.boot.util.Instantiator.AvailableParameters; @@ -104,18 +105,49 @@ void getUsingClassNameInjectsCustomParameter() { } @Test - void getInjectCustomizers() { + void getInjectStringMembersCustomizer() { this.environment.setProperty("logging.structured.json.rename.spring", "test"); SpringFactoriesLoader factoriesLoader = mock(SpringFactoriesLoader.class); - StructuredLoggingJsonMembersCustomizer customizer = (members) -> members - .applyingValueProcessor(ValueProcessor.of(String.class, String::toUpperCase)); - given(factoriesLoader.load(any(), any(ArgumentResolver.class))).willReturn(List.of(customizer)); + given(factoriesLoader.load(any(), any(ArgumentResolver.class))) + .willReturn(List.of(new StringMembersStructuredLoggingJsonMembersCustomizer())); StructuredLogFormatterFactory factory = new StructuredLogFormatterFactory<>(factoriesLoader, LogEvent.class, this.environment, this::addAvailableParameters, this::addCommonFormatters); - CutomizedFormatter formatter = (CutomizedFormatter) factory.get(CutomizedFormatter.class.getName()); + CustomizedFormatter formatter = (CustomizedFormatter) factory.get(CustomizedFormatter.class.getName()); assertThat(formatter.format(new LogEvent())).contains("\"test\":\"BOOT\""); } + @Test + void getInjectObjectMembersCustomizer() { + this.environment.setProperty("logging.structured.json.rename.spring", "test"); + SpringFactoriesLoader factoriesLoader = mock(SpringFactoriesLoader.class); + given(factoriesLoader.load(any(), any(ArgumentResolver.class))) + .willReturn(List.of(new ObjectMembersStructuredLoggingJsonMembersCustomizer())); + StructuredLogFormatterFactory factory = new StructuredLogFormatterFactory<>(factoriesLoader, + LogEvent.class, this.environment, this::addAvailableParameters, this::addCommonFormatters); + CustomizedFormatter formatter = (CustomizedFormatter) factory.get(CustomizedFormatter.class.getName()); + assertThat(formatter.format(new LogEvent())).contains("\"test\":\"BOOT\""); + } + + static class StringMembersStructuredLoggingJsonMembersCustomizer + implements StructuredLoggingJsonMembersCustomizer { + + @Override + public void customize(Members members) { + members.applyingValueProcessor(ValueProcessor.of(String.class, String::toUpperCase)); + } + + } + + static class ObjectMembersStructuredLoggingJsonMembersCustomizer + implements StructuredLoggingJsonMembersCustomizer { + + @Override + public void customize(Members members) { + members.applyingValueProcessor(ValueProcessor.of(String.class, String::toUpperCase)); + } + + } + static class LogEvent { } @@ -167,9 +199,9 @@ public String format(DifferentLogEvent event) { } - static class CutomizedFormatter extends JsonWriterStructuredLogFormatter { + static class CustomizedFormatter extends JsonWriterStructuredLogFormatter { - CutomizedFormatter(StructuredLoggingJsonMembersCustomizer customizer) { + CustomizedFormatter(StructuredLoggingJsonMembersCustomizer customizer) { super((members) -> members.add("spring", "boot"), customizer); } From 5cff43ddff85868defac1dac8e47ae1b31b5cf40 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 28 Nov 2024 11:33:37 +0000 Subject: [PATCH 017/203] Link to EnableMethodSecurity instead of EnableGlobalMethodSecurity Closes gh-43308 --- .../antora/modules/reference/pages/web/spring-security.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/web/spring-security.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/web/spring-security.adoc index cc5c4cadd68b..bfdff877ab32 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/web/spring-security.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/web/spring-security.adoc @@ -3,7 +3,7 @@ If {url-spring-security-site}[Spring Security] is on the classpath, then web applications are secured by default. Spring Boot relies on Spring Security’s content-negotiation strategy to determine whether to use `httpBasic` or `formLogin`. -To add method-level security to a web application, you can also add javadoc:org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity[format=annotation] with your desired settings. +To add method-level security to a web application, you can also add javadoc:org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity[format=annotation] with your desired settings. Additional information can be found in the {url-spring-security-docs}/servlet/authorization/method-security.html[Spring Security Reference Guide]. The default javadoc:org.springframework.security.core.userdetails.UserDetailsService[] has a single user. From 34ac0450739a08589352e63987066dfde35ed357 Mon Sep 17 00:00:00 2001 From: Yanming Zhou Date: Thu, 28 Nov 2024 17:45:32 +0800 Subject: [PATCH 018/203] Document StructuredLoggingJsonMembersCustomizer constructor params See gh-43314 --- .../StructuredLoggingJsonMembersCustomizer.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/structured/StructuredLoggingJsonMembersCustomizer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/structured/StructuredLoggingJsonMembersCustomizer.java index 67040b39149a..48589cb4e9ae 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/structured/StructuredLoggingJsonMembersCustomizer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/structured/StructuredLoggingJsonMembersCustomizer.java @@ -25,6 +25,15 @@ *

* An implementation may be provided using the {@code logging.structured.json.customizer} * property. + *

+ * {@code StructuredLoggingJsonMembersCustomizer} implementations may optionally take the + * following constructor parameters: + *

    + *
  • {@link org.springframework.core.env.Environment} - The Spring + * {@code Environment}.
  • + *
  • {@link ch.qos.logback.classic.pattern.ThrowableProxyConverter} - The Logback + * {@code ThrowableProxyConverter} (available only if Logback is using).
  • + *
* * @param the type being written * @author Phillip Webb From 15109b2eb2755ea5cded7dd3cc4d8d1a0a7cc7f4 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 28 Nov 2024 13:38:32 +0000 Subject: [PATCH 019/203] Polish "Document StructuredLoggingJsonMembersCustomizer constructor params" See gh-43314 --- ...StructuredLoggingJsonMembersCustomizer.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/structured/StructuredLoggingJsonMembersCustomizer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/structured/StructuredLoggingJsonMembersCustomizer.java index 48589cb4e9ae..087b2b180e26 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/structured/StructuredLoggingJsonMembersCustomizer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/structured/StructuredLoggingJsonMembersCustomizer.java @@ -16,23 +16,27 @@ package org.springframework.boot.logging.structured; +import ch.qos.logback.classic.pattern.ThrowableProxyConverter; + import org.springframework.boot.json.JsonWriter; import org.springframework.boot.json.JsonWriter.Members; +import org.springframework.core.env.Environment; /** - * Customer that can be injected into a {@link StructuredLogFormatter} implementations to + * Customizer that can be injected into {@link StructuredLogFormatter} implementations to * customize {@link JsonWriter} {@link Members}. *

* An implementation may be provided using the {@code logging.structured.json.customizer} * property. *

- * {@code StructuredLoggingJsonMembersCustomizer} implementations may optionally take the - * following constructor parameters: + * Implementing classes can declare the following parameter types in the constructor: + *

    + *
  • {@link Environment}
  • + *
+ * When using Logback, implementing classes can also use the following parameter types in + * the constructor: *
    - *
  • {@link org.springframework.core.env.Environment} - The Spring - * {@code Environment}.
  • - *
  • {@link ch.qos.logback.classic.pattern.ThrowableProxyConverter} - The Logback - * {@code ThrowableProxyConverter} (available only if Logback is using).
  • + *
  • {@link ThrowableProxyConverter}
  • *
* * @param the type being written From f3a161afdde5cfb7a815c83b9f67704e5fc0afb3 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 28 Nov 2024 14:07:27 +0000 Subject: [PATCH 020/203] Enable relaxed matching of enabled and access properties The lowercase form of the endpoint ID needs to be used so that relaxed matching of properties, as provided by ConfigurationPropertySources, works as intended. Without this change the id of the endpoint in a property had to be an exact match of the endpoint's ID. Closes gh-43302 --- .../PropertiesEndpointAccessResolver.java | 4 ++-- ...PropertiesEndpointAccessResolverTests.java | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/PropertiesEndpointAccessResolver.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/PropertiesEndpointAccessResolver.java index 0f05abef2615..681516eb84b3 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/PropertiesEndpointAccessResolver.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/PropertiesEndpointAccessResolver.java @@ -80,10 +80,10 @@ private static Access determineDefaultAccess(PropertyResolver properties) { @Override public Access accessFor(EndpointId endpointId, Access defaultAccess) { return this.accessCache.computeIfAbsent(endpointId, - (key) -> resolveAccess(endpointId, defaultAccess).cap(this.maxPermittedAccess)); + (key) -> resolveAccess(endpointId.toLowerCaseString(), defaultAccess).cap(this.maxPermittedAccess)); } - private Access resolveAccess(EndpointId endpointId, Access defaultAccess) { + private Access resolveAccess(String endpointId, Access defaultAccess) { String accessKey = "management.endpoint.%s.access".formatted(endpointId); String enabledKey = "management.endpoint.%s.enabled".formatted(endpointId); Access access = this.properties.getProperty(accessKey, Access.class); diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/PropertiesEndpointAccessResolverTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/PropertiesEndpointAccessResolverTests.java index 9907b4b712bb..cd15b1e6e253 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/PropertiesEndpointAccessResolverTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/PropertiesEndpointAccessResolverTests.java @@ -20,6 +20,7 @@ import org.springframework.boot.actuate.endpoint.Access; import org.springframework.boot.actuate.endpoint.EndpointId; +import org.springframework.boot.context.properties.source.ConfigurationPropertySources; import org.springframework.boot.context.properties.source.MutuallyExclusiveConfigurationPropertiesException; import org.springframework.mock.env.MockEnvironment; @@ -35,6 +36,10 @@ class PropertiesEndpointAccessResolverTests { private final MockEnvironment environment = new MockEnvironment(); + PropertiesEndpointAccessResolverTests() { + ConfigurationPropertySources.attach(this.environment); + } + @Test void whenNoPropertiesAreConfiguredThenAccessForReturnsEndpointsDefaultAccess() { assertThat(accessResolver().accessFor(EndpointId.of("test"), Access.READ_ONLY)).isEqualTo(Access.READ_ONLY); @@ -52,6 +57,13 @@ void whenAccessForEndpointIsConfiguredThenAccessForReturnsIt() { assertThat(accessResolver().accessFor(EndpointId.of("test"), Access.READ_ONLY)).isEqualTo(Access.UNRESTRICTED); } + @Test + void whenAccessForEndpointWithCamelCaseIdIsConfiguredThenAccessForReturnsIt() { + this.environment.withProperty("management.endpoint.alpha-bravo.access", Access.UNRESTRICTED.name()); + assertThat(accessResolver().accessFor(EndpointId.of("alphaBravo"), Access.READ_ONLY)) + .isEqualTo(Access.UNRESTRICTED); + } + @Test void whenAccessForEndpointAndDefaultAccessForAllEndpointsAreConfiguredAccessForReturnsAccessForEndpoint() { this.environment.withProperty("management.endpoint.test.access", Access.NONE.name()) @@ -83,6 +95,13 @@ void whenEndpointIsEnabledAccessForReturnsUnrestricted() { assertThat(accessResolver().accessFor(EndpointId.of("test"), Access.READ_ONLY)).isEqualTo(Access.UNRESTRICTED); } + @Test + void whenEndpointWithCamelCaseIdIsEnabledAccessForReturnsUnrestricted() { + this.environment.withProperty("management.endpoint.alpha-bravo.enabled", "true"); + assertThat(accessResolver().accessFor(EndpointId.of("alphaBravo"), Access.READ_ONLY)) + .isEqualTo(Access.UNRESTRICTED); + } + @Test void whenEnabledByDefaultAndDefaultAccessAreBothConfiguredResolverCreationThrows() { this.environment.withProperty("management.endpoints.enabled-by-default", "true") From 82652aba499a6c579d7c26adf829e8ce38a16806 Mon Sep 17 00:00:00 2001 From: Tran Ngoc Nhan Date: Fri, 29 Nov 2024 02:21:32 +0700 Subject: [PATCH 021/203] Fix Servlet and JPA javadoc links See gh-43320 --- spring-boot-project/spring-boot-dependencies/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 51c60d3505f4..1be965409399 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -758,7 +758,7 @@ bom { links { site(version -> "https://jakarta.ee/specifications/persistence/%s.%s" .formatted(version.major(), version.minor())) - javadoc(version -> "https://jakarta.ee/specifications/persistence/%s.%s/apidocs" + javadoc(version -> "https://jakarta.ee/specifications/persistence/%s.%s/apidocs/jakarta.persistence" .formatted(version.major(), version.minor()), "jakarta.persistence") releaseNotes(version -> "https://github.com/jakartaee/persistence/releases/tag/%s.%s-%s-RELEASE" .formatted(version.major(), version.minor(), version)) @@ -773,7 +773,7 @@ bom { links { site(version -> "https://jakarta.ee/specifications/servlet/%s.%s" .formatted(version.major(), version.minor())) - javadoc(version -> "https://jakarta.ee/specifications/servlet/%s.%s/apidocs" + javadoc(version -> "https://jakarta.ee/specifications/servlet/%s.%s/apidocs/jakarta.servlet" .formatted(version.major(), version.minor()), "jakarta.servlet") } } From 26b1d7447028b684010c58c4620f224cb63742df Mon Sep 17 00:00:00 2001 From: Stefano Cordio Date: Fri, 29 Nov 2024 08:32:03 +0100 Subject: [PATCH 022/203] Fix link to proxyBeanMethods in @AutoConfiguration javadoc See gh-43323 --- .../springframework/boot/autoconfigure/AutoConfiguration.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfiguration.java index a7e2d967a44a..0bf59e966ab5 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfiguration.java @@ -35,8 +35,8 @@ * Indicates that a class provides configuration that can be automatically applied by * Spring Boot. Auto-configuration classes are regular * {@link Configuration @Configuration} with the exception that - * {@literal Configuration#proxyBeanMethods() proxyBeanMethods} is always {@code false}. - * They are located using {@link ImportCandidates}. + * {@link Configuration#proxyBeanMethods() proxyBeanMethods} is always {@code false}. They + * are located using {@link ImportCandidates}. *

* Generally auto-configuration classes are marked as {@link Conditional @Conditional} * (most often using {@link ConditionalOnClass @ConditionalOnClass} and From aaaeddcd7d832d345ac21484df799a6626504c4b Mon Sep 17 00:00:00 2001 From: Yanming Zhou Date: Fri, 29 Nov 2024 08:42:21 +0800 Subject: [PATCH 023/203] Update javadoc to describe registration through spring.factories See gh-43313 --- .../structured/StructuredLoggingJsonMembersCustomizer.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/structured/StructuredLoggingJsonMembersCustomizer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/structured/StructuredLoggingJsonMembersCustomizer.java index 087b2b180e26..d27a73af82d4 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/structured/StructuredLoggingJsonMembersCustomizer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/structured/StructuredLoggingJsonMembersCustomizer.java @@ -27,7 +27,9 @@ * customize {@link JsonWriter} {@link Members}. *

* An implementation may be provided using the {@code logging.structured.json.customizer} - * property. + * property. Alternatively, implementations can be registered in + * {@code META-INF/spring.factories} under the key + * {@code org.springframework.boot.logging.structured.StructuredLoggingJsonMembersCustomizer}. *

* Implementing classes can declare the following parameter types in the constructor: *

    From 859c235a95ec404cb3f514054cd73bdf9565fafb Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Thu, 28 Nov 2024 23:17:38 +0900 Subject: [PATCH 024/203] Polish See gh-43316 --- .../autoconfigure/logging/otlp/OtlpLoggingProperties.java | 2 +- .../boot/autoconfigure/jms/JmsProperties.java | 6 +++--- ...emetryLoggingDockerComposeConnectionDetailsFactory.java | 6 +++--- ...emetryTracingDockerComposeConnectionDetailsFactory.java | 6 +++--- .../antora/modules/reference/pages/actuator/endpoints.adoc | 2 +- ... => TestcontainersParallelStartupIntegrationTests.java} | 4 ++-- ...elStartupWithImportTestcontainersIntegrationTests.java} | 4 ++-- .../src/docs/antora/modules/maven-plugin/pages/aot.adoc | 2 +- .../assertj/ScheduledExecutorServiceAssert.java | 7 +++---- .../testsupport/assertj/SimpleAsyncTaskExecutorAssert.java | 4 ++-- .../springframework/boot/jackson/JsonMixinModuleTests.java | 2 +- 11 files changed, 22 insertions(+), 23 deletions(-) rename spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/lifecycle/{TestContainersParallelStartupIntegrationTests.java => TestcontainersParallelStartupIntegrationTests.java} (95%) rename spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/lifecycle/{TestContainersParallelStartupWithImportTestcontainersIntegrationTests.java => TestcontainersParallelStartupWithImportTestcontainersIntegrationTests.java} (94%) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/otlp/OtlpLoggingProperties.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/otlp/OtlpLoggingProperties.java index 4d06499f7ab7..9a2d2fc446ce 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/otlp/OtlpLoggingProperties.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/otlp/OtlpLoggingProperties.java @@ -50,7 +50,7 @@ public class OtlpLoggingProperties { private Duration connectTimeout = Duration.ofSeconds(10); /** - * Transport used to send the spans. + * Transport used to send the logs. */ private Transport transport = Transport.HTTP; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/JmsProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/JmsProperties.java index aaf6c8a9ada6..126ffd065f31 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/JmsProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/JmsProperties.java @@ -187,9 +187,9 @@ public static class Listener { private Duration receiveTimeout = Duration.ofSeconds(1); /** - * Specify the maximum number of messages to process in one task. By default, - * unlimited unless a SchedulingTaskExecutor is configured on the listener (10 - * messages), as it indicates a preference for short-lived tasks. + * Maximum number of messages to process in one task. By default, unlimited unless + * a SchedulingTaskExecutor is configured on the listener (10 messages), as it + * indicates a preference for short-lived tasks. */ private Integer maxMessagesPerTask; diff --git a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/service/connection/otlp/OpenTelemetryLoggingDockerComposeConnectionDetailsFactory.java b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/service/connection/otlp/OpenTelemetryLoggingDockerComposeConnectionDetailsFactory.java index 92ea28f71732..a4a6da3abc9c 100644 --- a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/service/connection/otlp/OpenTelemetryLoggingDockerComposeConnectionDetailsFactory.java +++ b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/service/connection/otlp/OpenTelemetryLoggingDockerComposeConnectionDetailsFactory.java @@ -55,19 +55,19 @@ private static final class OpenTelemetryLoggingDockerComposeConnectionDetails ex private final int grpcPort; - private final int httPort; + private final int httpPort; private OpenTelemetryLoggingDockerComposeConnectionDetails(RunningService source) { super(source); this.host = source.host(); this.grpcPort = source.ports().get(OTLP_GRPC_PORT); - this.httPort = source.ports().get(OTLP_HTTP_PORT); + this.httpPort = source.ports().get(OTLP_HTTP_PORT); } @Override public String getUrl(Transport transport) { int port = switch (transport) { - case HTTP -> this.httPort; + case HTTP -> this.httpPort; case GRPC -> this.grpcPort; }; return "http://%s:%d/v1/logs".formatted(this.host, port); diff --git a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/service/connection/otlp/OpenTelemetryTracingDockerComposeConnectionDetailsFactory.java b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/service/connection/otlp/OpenTelemetryTracingDockerComposeConnectionDetailsFactory.java index 725600e063af..abacdf68bfaf 100644 --- a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/service/connection/otlp/OpenTelemetryTracingDockerComposeConnectionDetailsFactory.java +++ b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/service/connection/otlp/OpenTelemetryTracingDockerComposeConnectionDetailsFactory.java @@ -56,19 +56,19 @@ private static final class OpenTelemetryTracingDockerComposeConnectionDetails ex private final int grpcPort; - private final int httPort; + private final int httpPort; private OpenTelemetryTracingDockerComposeConnectionDetails(RunningService source) { super(source); this.host = source.host(); this.grpcPort = source.ports().get(OTLP_GRPC_PORT); - this.httPort = source.ports().get(OTLP_HTTP_PORT); + this.httpPort = source.ports().get(OTLP_HTTP_PORT); } @Override public String getUrl(Transport transport) { int port = switch (transport) { - case HTTP -> this.httPort; + case HTTP -> this.httpPort; case GRPC -> this.grpcPort; }; return "http://%s:%d/v1/traces".formatted(this.host, port); diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/actuator/endpoints.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/actuator/endpoints.adoc index 98cfc40bd740..9447c5830385 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/actuator/endpoints.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/actuator/endpoints.adoc @@ -307,7 +307,7 @@ Information returned by the `/env`, `/configprops` and `/quartz` endpoints can b Values can only be viewed in an unsanitized form when: -- The `show-values` property has been set to something other than `NEVER` +- The `show-values` property has been set to something other than `never` - No custom xref:how-to:actuator.adoc#howto.actuator.customizing-sanitization[`SanitizingFunction`] beans apply The `show-values` property can be configured for sanitizable endpoints to one of the following values: diff --git a/spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/lifecycle/TestContainersParallelStartupIntegrationTests.java b/spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/lifecycle/TestcontainersParallelStartupIntegrationTests.java similarity index 95% rename from spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/lifecycle/TestContainersParallelStartupIntegrationTests.java rename to spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/lifecycle/TestcontainersParallelStartupIntegrationTests.java index 0dde259bbaf4..458c5418a113 100644 --- a/spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/lifecycle/TestContainersParallelStartupIntegrationTests.java +++ b/spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/lifecycle/TestcontainersParallelStartupIntegrationTests.java @@ -22,7 +22,7 @@ import org.springframework.boot.test.system.CapturedOutput; import org.springframework.boot.test.system.OutputCaptureExtension; -import org.springframework.boot.testcontainers.lifecycle.TestContainersParallelStartupIntegrationTests.ContainerConfig; +import org.springframework.boot.testcontainers.lifecycle.TestcontainersParallelStartupIntegrationTests.ContainerConfig; import org.springframework.boot.testsupport.container.DisabledIfDockerUnavailable; import org.springframework.boot.testsupport.container.TestImage; import org.springframework.context.annotation.Bean; @@ -43,7 +43,7 @@ @TestPropertySource(properties = "spring.testcontainers.beans.startup=parallel") @DisabledIfDockerUnavailable @ExtendWith(OutputCaptureExtension.class) -class TestContainersParallelStartupIntegrationTests { +class TestcontainersParallelStartupIntegrationTests { @Test void startsInParallel(CapturedOutput out) { diff --git a/spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/lifecycle/TestContainersParallelStartupWithImportTestcontainersIntegrationTests.java b/spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/lifecycle/TestcontainersParallelStartupWithImportTestcontainersIntegrationTests.java similarity index 94% rename from spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/lifecycle/TestContainersParallelStartupWithImportTestcontainersIntegrationTests.java rename to spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/lifecycle/TestcontainersParallelStartupWithImportTestcontainersIntegrationTests.java index e3a9cfb57fbb..0c7ea77e2105 100644 --- a/spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/lifecycle/TestContainersParallelStartupWithImportTestcontainersIntegrationTests.java +++ b/spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/lifecycle/TestcontainersParallelStartupWithImportTestcontainersIntegrationTests.java @@ -24,7 +24,7 @@ import org.springframework.boot.test.system.CapturedOutput; import org.springframework.boot.test.system.OutputCaptureExtension; import org.springframework.boot.testcontainers.context.ImportTestcontainers; -import org.springframework.boot.testcontainers.lifecycle.TestContainersParallelStartupWithImportTestcontainersIntegrationTests.Containers; +import org.springframework.boot.testcontainers.lifecycle.TestcontainersParallelStartupWithImportTestcontainersIntegrationTests.Containers; import org.springframework.boot.testsupport.container.DisabledIfDockerUnavailable; import org.springframework.boot.testsupport.container.TestImage; import org.springframework.test.context.TestPropertySource; @@ -42,7 +42,7 @@ @DisabledIfDockerUnavailable @ExtendWith(OutputCaptureExtension.class) @ImportTestcontainers(Containers.class) -class TestContainersParallelStartupWithImportTestcontainersIntegrationTests { +class TestcontainersParallelStartupWithImportTestcontainersIntegrationTests { @Test void startsInParallel(CapturedOutput out) { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/pages/aot.adoc b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/pages/aot.adoc index b3e53cecef4a..442f2877bf78 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/pages/aot.adoc +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/pages/aot.adoc @@ -43,7 +43,7 @@ The `native` profile configures the following: [WARNING] ==== -The use of the raw classpath means that native image does not know about the generated `MANIFEST`. +The use of the raw classpath means that native image does not know about the generated `MANIFEST.MF`. If you need to read the content of the manifest in a native image, for instance to get the implementation version of your application, configure the `classesDirectory` option to use the regular jar. ==== diff --git a/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/assertj/ScheduledExecutorServiceAssert.java b/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/assertj/ScheduledExecutorServiceAssert.java index 50ba12648662..3c6dc4f0221a 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/assertj/ScheduledExecutorServiceAssert.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/assertj/ScheduledExecutorServiceAssert.java @@ -19,7 +19,6 @@ import java.lang.reflect.Method; import java.util.concurrent.ExecutionException; import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.assertj.core.api.AbstractAssert; @@ -28,7 +27,7 @@ import org.springframework.util.ReflectionUtils; /** - * AssertJ {@link Assert} for {@link ScheduledThreadPoolExecutor}. + * AssertJ {@link Assert} for {@link ScheduledExecutorService}. * * @author Mike Turbe * @author Moritz Halbritter @@ -82,9 +81,9 @@ private boolean producesVirtualThreads() { } /** - * Creates a new assertion class with the given {@link ScheduledExecutorService}. + * Creates a new assertion instance with the given {@link ScheduledExecutorService}. * @param actual the {@link ScheduledExecutorService} - * @return the assertion class + * @return the assertion instance */ public static ScheduledExecutorServiceAssert assertThat(ScheduledExecutorService actual) { return new ScheduledExecutorServiceAssert(actual); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/assertj/SimpleAsyncTaskExecutorAssert.java b/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/assertj/SimpleAsyncTaskExecutorAssert.java index 8b6b25e7a543..9df464da2b81 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/assertj/SimpleAsyncTaskExecutorAssert.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/assertj/SimpleAsyncTaskExecutorAssert.java @@ -73,9 +73,9 @@ private boolean producesVirtualThreads() { } /** - * Creates a new assertion class with the given {@link SimpleAsyncTaskExecutor}. + * Creates a new assertion instance with the given {@link SimpleAsyncTaskExecutor}. * @param actual the {@link SimpleAsyncTaskExecutor} - * @return the assertion class + * @return the assertion instance */ public static SimpleAsyncTaskExecutorAssert assertThat(SimpleAsyncTaskExecutor actual) { return new SimpleAsyncTaskExecutorAssert(actual); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jackson/JsonMixinModuleTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jackson/JsonMixinModuleTests.java index 6bedd39637c8..9a160a02c424 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jackson/JsonMixinModuleTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jackson/JsonMixinModuleTests.java @@ -55,7 +55,7 @@ void closeContext() { } @Test - void jsonWithModuleEmptyMixInWithEmptyTypesShouldFailed() { + void jsonWithModuleEmptyMixInWithEmptyTypesShouldFail() { assertThatExceptionOfType(BeanCreationException.class).isThrownBy(() -> load(EmptyMixIn.class)) .withMessageContaining("Error creating bean with name 'jsonMixinModule'") .withStackTraceContaining("@JsonMixin annotation on class " From 615b1993643e3c21aed8b2aeeb057bcda977002e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Fri, 29 Nov 2024 10:34:57 +0100 Subject: [PATCH 025/203] Update copyright year of changed file See gh-43316 --- .../boot/testsupport/assertj/SimpleAsyncTaskExecutorAssert.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/assertj/SimpleAsyncTaskExecutorAssert.java b/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/assertj/SimpleAsyncTaskExecutorAssert.java index 9df464da2b81..5e8fa4752e33 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/assertj/SimpleAsyncTaskExecutorAssert.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/assertj/SimpleAsyncTaskExecutorAssert.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. From b86b81da35961a86ed5373344e95bf0069c1d6ff Mon Sep 17 00:00:00 2001 From: BenchmarkingBuffalo <46448799+benchmarkingbuffalo@users.noreply.github.com> Date: Sat, 30 Nov 2024 22:25:47 +0100 Subject: [PATCH 026/203] Remove prohibited undertow upgrade restriction See gh-43333 --- spring-boot-project/spring-boot-dependencies/build.gradle | 4 ---- 1 file changed, 4 deletions(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 1be965409399..90342193570f 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2468,10 +2468,6 @@ bom { } } library("Undertow", "2.3.17.Final") { - prohibit { - versionRange "[2.3.18.Final]" - because "requires new framework patch due to regression (https://issues.redhat.com/browse/UNDERTOW-2512)" - } group("io.undertow") { modules = [ "undertow-core", From d81678016e2a08ac0cade7e89e27c4bb6ba0852c Mon Sep 17 00:00:00 2001 From: Yanming Zhou Date: Mon, 2 Dec 2024 16:34:29 +0800 Subject: [PATCH 027/203] Restore System property in Logging section of the reference documentation Before this commit, it is rendered as an unexpected link with simple class name, it should be full qualified class name. See gh-43341 --- .../docs/antora/modules/reference/pages/features/logging.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/logging.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/logging.adoc index 20defb85c5f4..86daea02277c 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/logging.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/logging.adoc @@ -287,7 +287,7 @@ logging: The various logging systems can be activated by including the appropriate libraries on the classpath and can be further customized by providing a suitable configuration file in the root of the classpath or in a location specified by the following Spring javadoc:org.springframework.core.env.Environment[] property: configprop:logging.config[]. -You can force Spring Boot to use a particular logging system by using the javadoc:org.springframework.boot.logging.LoggingSystem[] system property. +You can force Spring Boot to use a particular logging system by using the `org.springframework.boot.logging.LoggingSystem` system property. The value should be the fully qualified class name of a javadoc:org.springframework.boot.logging.LoggingSystem[] implementation. You can also disable Spring Boot's logging configuration entirely by using a value of `none`. From bd367803d1852251c2ec1e65f1dd20ccedfae637 Mon Sep 17 00:00:00 2001 From: Jae-Young98 Date: Mon, 2 Dec 2024 18:31:21 +0900 Subject: [PATCH 028/203] Remove redundant null check for sorter See gh-43343 --- .../springframework/boot/context/annotation/Configurations.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/annotation/Configurations.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/annotation/Configurations.java index b00121071f26..84b137cf176f 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/annotation/Configurations.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/annotation/Configurations.java @@ -92,7 +92,7 @@ protected Configurations(UnaryOperator>> sorter, Collection< Assert.notNull(classes, "Classes must not be null"); sorter = (sorter != null) ? sorter : UnaryOperator.identity(); Collection> sorted = sorter.apply(classes); - this.sorter = (sorter != null) ? sorter : UnaryOperator.identity(); + this.sorter = sorter; this.classes = Collections.unmodifiableSet(new LinkedHashSet<>(sorted)); this.beanNameGenerator = beanNameGenerator; } From 07bc5f256336790132a83c465a9b537ad66b2b05 Mon Sep 17 00:00:00 2001 From: Moritz Halbritter Date: Mon, 2 Dec 2024 11:39:37 +0100 Subject: [PATCH 029/203] Polish "Remove redundant null check for sorter" See gh-43343 --- .../boot/context/annotation/Configurations.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/annotation/Configurations.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/annotation/Configurations.java index 84b137cf176f..744c04d3f4a4 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/annotation/Configurations.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/annotation/Configurations.java @@ -90,9 +90,8 @@ protected Configurations(Collection> classes) { protected Configurations(UnaryOperator>> sorter, Collection> classes, Function, String> beanNameGenerator) { Assert.notNull(classes, "Classes must not be null"); - sorter = (sorter != null) ? sorter : UnaryOperator.identity(); - Collection> sorted = sorter.apply(classes); - this.sorter = sorter; + this.sorter = (sorter != null) ? sorter : UnaryOperator.identity(); + Collection> sorted = this.sorter.apply(classes); this.classes = Collections.unmodifiableSet(new LinkedHashSet<>(sorted)); this.beanNameGenerator = beanNameGenerator; } From c5d41f14697927babcf4ae0d0ffe07b49fcaab76 Mon Sep 17 00:00:00 2001 From: BenchmarkingBuffalo <46448799+benchmarkingbuffalo@users.noreply.github.com> Date: Sun, 1 Dec 2024 00:00:04 +0100 Subject: [PATCH 030/203] Make UserDetailsServiceAutoConfiguration conditional on servlet app See gh-43334 --- .../servlet/UserDetailsServiceAutoConfiguration.java | 4 ++++ .../servlet/UserDetailsServiceAutoConfigurationTests.java | 7 ++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/UserDetailsServiceAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/UserDetailsServiceAutoConfiguration.java index eac402fe0afc..a6b803083720 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/UserDetailsServiceAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/UserDetailsServiceAutoConfiguration.java @@ -31,6 +31,8 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; import org.springframework.boot.autoconfigure.security.SecurityProperties; import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration.MissingAlternativeOrUserPropertiesConfigured; import org.springframework.context.annotation.Bean; @@ -53,6 +55,7 @@ * @author Dave Syer * @author Rob Winch * @author Madhura Bhave + * @author Lasse Wulff * @since 2.0.0 */ @AutoConfiguration @@ -61,6 +64,7 @@ @ConditionalOnBean(ObjectPostProcessor.class) @ConditionalOnMissingBean(value = { AuthenticationManager.class, AuthenticationProvider.class, UserDetailsService.class, AuthenticationManagerResolver.class }, type = "org.springframework.security.oauth2.jwt.JwtDecoder") +@ConditionalOnWebApplication(type = Type.SERVLET) public class UserDetailsServiceAutoConfiguration { private static final String NOOP_PASSWORD_PREFIX = "{noop}"; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/UserDetailsServiceAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/UserDetailsServiceAutoConfigurationTests.java index 6de9275db26b..d80e3a686c7e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/UserDetailsServiceAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/UserDetailsServiceAutoConfigurationTests.java @@ -26,7 +26,7 @@ import org.springframework.boot.autoconfigure.security.SecurityProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.test.context.FilteredClassLoader; -import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.boot.test.context.runner.WebApplicationContextRunner; import org.springframework.boot.test.system.CapturedOutput; import org.springframework.boot.test.system.OutputCaptureExtension; import org.springframework.context.annotation.Bean; @@ -56,11 +56,12 @@ * * @author Madhura Bhave * @author HaiTao Zhang + * @author Lasse Wulff */ @ExtendWith(OutputCaptureExtension.class) class UserDetailsServiceAutoConfigurationTests { - private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() .withUserConfiguration(TestSecurityConfiguration.class) .withConfiguration(AutoConfigurations.of(UserDetailsServiceAutoConfiguration.class)); @@ -192,7 +193,7 @@ void userDetailsServiceWhenRelyingPartyRegistrationRepositoryPresentAndPasswordC .run(((context) -> assertThat(context).hasSingleBean(InMemoryUserDetailsManager.class))); } - private Function noOtherFormsOfAuthenticationOnTheClasspath() { + private Function noOtherFormsOfAuthenticationOnTheClasspath() { return (contextRunner) -> contextRunner .withClassLoader(new FilteredClassLoader(ClientRegistrationRepository.class, OpaqueTokenIntrospector.class, RelyingPartyRegistrationRepository.class)); From ff9fde0ef4a116bf13f0c5860414b0b2798fbdda Mon Sep 17 00:00:00 2001 From: Moritz Halbritter Date: Mon, 2 Dec 2024 13:30:36 +0100 Subject: [PATCH 031/203] Polish "Make UserDetailsServiceAutoConfiguration conditional on servlet app" See gh-43334 --- ...rDetailsServiceAutoConfigurationTests.java | 57 ++++++++++++++++--- 1 file changed, 48 insertions(+), 9 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/UserDetailsServiceAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/UserDetailsServiceAutoConfigurationTests.java index d80e3a686c7e..6c4ee3c918ec 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/UserDetailsServiceAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/UserDetailsServiceAutoConfigurationTests.java @@ -26,6 +26,8 @@ import org.springframework.boot.autoconfigure.security.SecurityProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.test.context.FilteredClassLoader; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner; import org.springframework.boot.test.context.runner.WebApplicationContextRunner; import org.springframework.boot.test.system.CapturedOutput; import org.springframework.boot.test.system.OutputCaptureExtension; @@ -57,6 +59,7 @@ * @author Madhura Bhave * @author HaiTao Zhang * @author Lasse Wulff + * @author Moritz Halbritter */ @ExtendWith(OutputCaptureExtension.class) class UserDetailsServiceAutoConfigurationTests { @@ -65,9 +68,31 @@ class UserDetailsServiceAutoConfigurationTests { .withUserConfiguration(TestSecurityConfiguration.class) .withConfiguration(AutoConfigurations.of(UserDetailsServiceAutoConfiguration.class)); + @Test + void shouldSupplyUserDetailsServiceInServletApp() { + this.contextRunner.with(AuthenticationExclude.servletApp()) + .run((context) -> assertThat(context).hasSingleBean(UserDetailsService.class)); + } + + @Test + void shouldNotSupplyUserDetailsServiceInReactiveApp() { + new ReactiveWebApplicationContextRunner().withUserConfiguration(TestSecurityConfiguration.class) + .withConfiguration(AutoConfigurations.of(UserDetailsServiceAutoConfiguration.class)) + .with(AuthenticationExclude.reactiveApp()) + .run((context) -> assertThat(context).doesNotHaveBean(UserDetailsService.class)); + } + + @Test + void shouldNotSupplyUserDetailsServiceInNonWebApp() { + new ApplicationContextRunner().withUserConfiguration(TestSecurityConfiguration.class) + .withConfiguration(AutoConfigurations.of(UserDetailsServiceAutoConfiguration.class)) + .with(AuthenticationExclude.noWebApp()) + .run((context) -> assertThat(context).doesNotHaveBean(UserDetailsService.class)); + } + @Test void testDefaultUsernamePassword(CapturedOutput output) { - this.contextRunner.with(noOtherFormsOfAuthenticationOnTheClasspath()).run((context) -> { + this.contextRunner.with(AuthenticationExclude.servletApp()).run((context) -> { UserDetailsService manager = context.getBean(UserDetailsService.class); assertThat(output).contains("Using generated security password:"); assertThat(manager.loadUserByUsername("user")).isNotNull(); @@ -129,7 +154,7 @@ void defaultUserNotCreatedIfResourceServerWithJWTIsUsed() { @Test void userDetailsServiceWhenPasswordEncoderAbsentAndDefaultPassword() { - this.contextRunner.with(noOtherFormsOfAuthenticationOnTheClasspath()) + this.contextRunner.with(AuthenticationExclude.servletApp()) .withUserConfiguration(TestSecurityConfiguration.class) .run(((context) -> { InMemoryUserDetailsManager userDetailsService = context.getBean(InMemoryUserDetailsManager.class); @@ -193,14 +218,8 @@ void userDetailsServiceWhenRelyingPartyRegistrationRepositoryPresentAndPasswordC .run(((context) -> assertThat(context).hasSingleBean(InMemoryUserDetailsManager.class))); } - private Function noOtherFormsOfAuthenticationOnTheClasspath() { - return (contextRunner) -> contextRunner - .withClassLoader(new FilteredClassLoader(ClientRegistrationRepository.class, OpaqueTokenIntrospector.class, - RelyingPartyRegistrationRepository.class)); - } - private void testPasswordEncoding(Class configClass, String providedPassword, String expectedPassword) { - this.contextRunner.with(noOtherFormsOfAuthenticationOnTheClasspath()) + this.contextRunner.with(AuthenticationExclude.servletApp()) .withClassLoader(new FilteredClassLoader(ClientRegistrationRepository.class, OpaqueTokenIntrospector.class, RelyingPartyRegistrationRepository.class)) .withUserConfiguration(configClass) @@ -212,6 +231,26 @@ private void testPasswordEncoding(Class configClass, String providedPassword, })); } + private static final class AuthenticationExclude { + + private static final FilteredClassLoader filteredClassLoader = new FilteredClassLoader( + ClientRegistrationRepository.class, OpaqueTokenIntrospector.class, + RelyingPartyRegistrationRepository.class); + + static Function servletApp() { + return (contextRunner) -> contextRunner.withClassLoader(filteredClassLoader); + } + + static Function reactiveApp() { + return (contextRunner) -> contextRunner.withClassLoader(filteredClassLoader); + } + + static Function noWebApp() { + return (contextRunner) -> contextRunner.withClassLoader(filteredClassLoader); + } + + } + @Configuration(proxyBeanMethods = false) static class TestAuthenticationManagerConfiguration { From 1f17e0125db8ed57c1e27da94561f7c6a765151a Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Sat, 30 Nov 2024 14:56:11 +0900 Subject: [PATCH 032/203] Fix property name in OnEnabledLoggingExportConditionTests See gh-43331 --- .../logging/OnEnabledLoggingExportConditionTests.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logging/OnEnabledLoggingExportConditionTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logging/OnEnabledLoggingExportConditionTests.java index 1bca2e10715a..61dca50d6e14 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logging/OnEnabledLoggingExportConditionTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logging/OnEnabledLoggingExportConditionTests.java @@ -90,7 +90,7 @@ void shouldMatchIfExporterPropertyIsTrue() { void exporterPropertyShouldOverrideGlobalPropertyIfTrue() { OnEnabledLoggingExportCondition condition = new OnEnabledLoggingExportCondition(); ConditionOutcome outcome = condition.getMatchOutcome(mockConditionContext( - Map.of("management.logging.enabled", "false", "management.otlp.logging.export.enabled", "true")), + Map.of("management.logging.export.enabled", "false", "management.otlp.logging.export.enabled", "true")), mockMetadata("otlp")); assertThat(outcome.isMatch()).isTrue(); assertThat(outcome.getMessage()) @@ -101,7 +101,7 @@ void exporterPropertyShouldOverrideGlobalPropertyIfTrue() { void exporterPropertyShouldOverrideGlobalPropertyIfFalse() { OnEnabledLoggingExportCondition condition = new OnEnabledLoggingExportCondition(); ConditionOutcome outcome = condition.getMatchOutcome(mockConditionContext( - Map.of("management.logging.enabled", "true", "management.otlp.logging.export.enabled", "false")), + Map.of("management.logging.export.enabled", "true", "management.otlp.logging.export.enabled", "false")), mockMetadata("otlp")); assertThat(outcome.isMatch()).isFalse(); assertThat(outcome.getMessage()) From d5344e3f1b54d7df9de82d52b96254fa78a6727b Mon Sep 17 00:00:00 2001 From: Moritz Halbritter Date: Mon, 2 Dec 2024 13:52:01 +0100 Subject: [PATCH 033/203] Polish "Fix property name in OnEnabledLoggingExportConditionTests" See gh-43331 --- .../OnEnabledLoggingExportConditionTests.java | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logging/OnEnabledLoggingExportConditionTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logging/OnEnabledLoggingExportConditionTests.java index 61dca50d6e14..3148e39453dc 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logging/OnEnabledLoggingExportConditionTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logging/OnEnabledLoggingExportConditionTests.java @@ -38,6 +38,10 @@ */ class OnEnabledLoggingExportConditionTests { + private static final String GLOBAL_PROPERTY_NAME = "management.logging.export.enabled"; + + private static final String OTLP_PROPERTY_NAME = "management.otlp.logging.export.enabled"; + @Test void shouldMatchIfNoPropertyIsSet() { OnEnabledLoggingExportCondition condition = new OnEnabledLoggingExportCondition(); @@ -49,8 +53,8 @@ void shouldMatchIfNoPropertyIsSet() { @Test void shouldNotMatchIfGlobalPropertyIsFalse() { OnEnabledLoggingExportCondition condition = new OnEnabledLoggingExportCondition(); - ConditionOutcome outcome = condition.getMatchOutcome( - mockConditionContext(Map.of("management.logging.export.enabled", "false")), mockMetadata("")); + ConditionOutcome outcome = condition + .getMatchOutcome(mockConditionContext(Map.of(GLOBAL_PROPERTY_NAME, "false")), mockMetadata("")); assertThat(outcome.isMatch()).isFalse(); assertThat(outcome.getMessage()) .isEqualTo("@ConditionalOnEnabledLoggingExport management.logging.export.enabled is false"); @@ -59,8 +63,8 @@ void shouldNotMatchIfGlobalPropertyIsFalse() { @Test void shouldMatchIfGlobalPropertyIsTrue() { OnEnabledLoggingExportCondition condition = new OnEnabledLoggingExportCondition(); - ConditionOutcome outcome = condition.getMatchOutcome( - mockConditionContext(Map.of("management.logging.export.enabled", "true")), mockMetadata("")); + ConditionOutcome outcome = condition.getMatchOutcome(mockConditionContext(Map.of(GLOBAL_PROPERTY_NAME, "true")), + mockMetadata("")); assertThat(outcome.isMatch()).isTrue(); assertThat(outcome.getMessage()) .isEqualTo("@ConditionalOnEnabledLoggingExport management.logging.export.enabled is true"); @@ -69,8 +73,8 @@ void shouldMatchIfGlobalPropertyIsTrue() { @Test void shouldNotMatchIfExporterPropertyIsFalse() { OnEnabledLoggingExportCondition condition = new OnEnabledLoggingExportCondition(); - ConditionOutcome outcome = condition.getMatchOutcome( - mockConditionContext(Map.of("management.otlp.logging.export.enabled", "false")), mockMetadata("otlp")); + ConditionOutcome outcome = condition.getMatchOutcome(mockConditionContext(Map.of(OTLP_PROPERTY_NAME, "false")), + mockMetadata("otlp")); assertThat(outcome.isMatch()).isFalse(); assertThat(outcome.getMessage()) .isEqualTo("@ConditionalOnEnabledLoggingExport management.otlp.logging.export.enabled is false"); @@ -79,8 +83,8 @@ void shouldNotMatchIfExporterPropertyIsFalse() { @Test void shouldMatchIfExporterPropertyIsTrue() { OnEnabledLoggingExportCondition condition = new OnEnabledLoggingExportCondition(); - ConditionOutcome outcome = condition.getMatchOutcome( - mockConditionContext(Map.of("management.otlp.logging.export.enabled", "true")), mockMetadata("otlp")); + ConditionOutcome outcome = condition.getMatchOutcome(mockConditionContext(Map.of(OTLP_PROPERTY_NAME, "true")), + mockMetadata("otlp")); assertThat(outcome.isMatch()).isTrue(); assertThat(outcome.getMessage()) .isEqualTo("@ConditionalOnEnabledLoggingExport management.otlp.logging.export.enabled is true"); @@ -89,8 +93,8 @@ void shouldMatchIfExporterPropertyIsTrue() { @Test void exporterPropertyShouldOverrideGlobalPropertyIfTrue() { OnEnabledLoggingExportCondition condition = new OnEnabledLoggingExportCondition(); - ConditionOutcome outcome = condition.getMatchOutcome(mockConditionContext( - Map.of("management.logging.export.enabled", "false", "management.otlp.logging.export.enabled", "true")), + ConditionOutcome outcome = condition.getMatchOutcome( + mockConditionContext(Map.of(GLOBAL_PROPERTY_NAME, "false", OTLP_PROPERTY_NAME, "true")), mockMetadata("otlp")); assertThat(outcome.isMatch()).isTrue(); assertThat(outcome.getMessage()) @@ -100,8 +104,8 @@ void exporterPropertyShouldOverrideGlobalPropertyIfTrue() { @Test void exporterPropertyShouldOverrideGlobalPropertyIfFalse() { OnEnabledLoggingExportCondition condition = new OnEnabledLoggingExportCondition(); - ConditionOutcome outcome = condition.getMatchOutcome(mockConditionContext( - Map.of("management.logging.export.enabled", "true", "management.otlp.logging.export.enabled", "false")), + ConditionOutcome outcome = condition.getMatchOutcome( + mockConditionContext(Map.of(GLOBAL_PROPERTY_NAME, "true", OTLP_PROPERTY_NAME, "false")), mockMetadata("otlp")); assertThat(outcome.isMatch()).isFalse(); assertThat(outcome.getMessage()) From d8565185e81ab11cd25c583809b871c7662862cb Mon Sep 17 00:00:00 2001 From: Wolfgang Kronberg Date: Fri, 29 Nov 2024 14:14:53 +0100 Subject: [PATCH 034/203] Accept Docker progress on numbers >2GB Update `ProgressUpdateEvent` to support images of a file size >2GB without provoking build failures. See gh-43328 --- .../platform/docker/ProgressUpdateEvent.java | 11 ++++++----- .../docker/ProgressUpdateEventTests.java | 16 ++++++++++++---- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/ProgressUpdateEvent.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/ProgressUpdateEvent.java index 271b6c19a2bd..5226ac57e3ce 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/ProgressUpdateEvent.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/ProgressUpdateEvent.java @@ -22,6 +22,7 @@ * An {@link UpdateEvent} that includes progress information. * * @author Phillip Webb + * @author Wolfgang Kronberg * @since 2.3.0 */ public abstract class ProgressUpdateEvent extends UpdateEvent { @@ -67,12 +68,12 @@ public String getProgress() { */ public static class ProgressDetail { - private final Integer current; + private final Long current; - private final Integer total; + private final Long total; @JsonCreator - public ProgressDetail(Integer current, Integer total) { + public ProgressDetail(Long current, Long total) { this.current = current; this.total = total; } @@ -81,7 +82,7 @@ public ProgressDetail(Integer current, Integer total) { * Return the current progress value. * @return the current progress */ - public int getCurrent() { + public long getCurrent() { return this.current; } @@ -89,7 +90,7 @@ public int getCurrent() { * Return the total progress possible value. * @return the total progress possible */ - public int getTotal() { + public long getTotal() { return this.total; } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/ProgressUpdateEventTests.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/ProgressUpdateEventTests.java index d6e2c0ace472..063e17ffc3a5 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/ProgressUpdateEventTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/ProgressUpdateEventTests.java @@ -28,6 +28,7 @@ * @param The event type * @author Phillip Webb * @author Scott Frederick + * @author Wolfgang Kronberg */ abstract class ProgressUpdateEventTests { @@ -44,6 +45,13 @@ void getProgressDetailsReturnsProgressDetails() { assertThat(event.getProgressDetail().getTotal()).isEqualTo(2); } + @Test + void getProgressDetailsReturnsProgressDetailsForLongNumbers() { + ProgressUpdateEvent event = createEvent("status", new ProgressDetail(4000000000L, 8000000000L), "progress"); + assertThat(event.getProgressDetail().getCurrent()).isEqualTo(4000000000L); + assertThat(event.getProgressDetail().getTotal()).isEqualTo(8000000000L); + } + @Test void getProgressReturnsProgress() { ProgressUpdateEvent event = createEvent(); @@ -52,24 +60,24 @@ void getProgressReturnsProgress() { @Test void progressDetailIsEmptyWhenCurrentIsNullReturnsTrue() { - ProgressDetail detail = new ProgressDetail(null, 2); + ProgressDetail detail = new ProgressDetail(null, 2L); assertThat(ProgressDetail.isEmpty(detail)).isTrue(); } @Test void progressDetailIsEmptyWhenTotalIsNullReturnsTrue() { - ProgressDetail detail = new ProgressDetail(1, null); + ProgressDetail detail = new ProgressDetail(1L, null); assertThat(ProgressDetail.isEmpty(detail)).isTrue(); } @Test void progressDetailIsEmptyWhenTotalAndCurrentAreNotNullReturnsFalse() { - ProgressDetail detail = new ProgressDetail(1, 2); + ProgressDetail detail = new ProgressDetail(1L, 2L); assertThat(ProgressDetail.isEmpty(detail)).isFalse(); } protected E createEvent() { - return createEvent("status", new ProgressDetail(1, 2), "progress"); + return createEvent("status", new ProgressDetail(1L, 2L), "progress"); } protected abstract E createEvent(String status, ProgressDetail progressDetail, String progress); From 0afbc0b23cc330e22bc58257ef2f9c2e11e66a94 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Mon, 2 Dec 2024 13:55:59 -0800 Subject: [PATCH 035/203] Polish 'Accept Docker progress on numbers >2GB' Restore `int` returns for existing methods and deprecate them in favor of a new `asPercentage()` method. See gh-43328 --- .../platform/docker/ProgressUpdateEvent.java | 33 ++++++++++++++++--- .../docker/TotalProgressListener.java | 10 ++---- .../docker/ProgressUpdateEventTests.java | 13 ++++++-- .../platform/docker/PullUpdateEventTests.java | 4 ++- 4 files changed, 44 insertions(+), 16 deletions(-) diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/ProgressUpdateEvent.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/ProgressUpdateEvent.java index 5226ac57e3ce..6ac289436341 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/ProgressUpdateEvent.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/ProgressUpdateEvent.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2024 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. @@ -81,19 +81,42 @@ public ProgressDetail(Long current, Long total) { /** * Return the current progress value. * @return the current progress + * @deprecated since 3.3.7 for removal in 3.5.0 in favor of + * {@link #asPercentage()} */ - public long getCurrent() { - return this.current; + @Deprecated(since = "3.3.7", forRemoval = true) + public int getCurrent() { + return (int) Long.min(this.current, Integer.MAX_VALUE); } /** * Return the total progress possible value. * @return the total progress possible + * @deprecated since 3.3.7 for removal in 3.5.0 in favor of + * {@link #asPercentage()} */ - public long getTotal() { - return this.total; + @Deprecated(since = "3.3.7", forRemoval = true) + public int getTotal() { + return (int) Long.min(this.total, Integer.MAX_VALUE); } + /** + * Return the progress as a percentage. + * @return the progress percentage + * @since 3.3.7 + */ + public int asPercentage() { + int percentage = (int) ((100.0 / this.total) * this.current); + return (percentage < 0) ? 0 : Math.min(percentage, 100); + } + + /** + * Return if the progress detail is considered empty. + * @param progressDetail the progress detail to check + * @return if the progress detail is empty + * @deprecated since 3.3.7 for removal in 3.5.0 + */ + @Deprecated(since = "3.3.7", forRemoval = true) public static boolean isEmpty(ProgressDetail progressDetail) { return progressDetail == null || progressDetail.current == null || progressDetail.total == null; } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/TotalProgressListener.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/TotalProgressListener.java index fa397c611f57..b81cfb85a364 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/TotalProgressListener.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/TotalProgressListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2024 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. @@ -89,10 +89,7 @@ private void publish(int fallback) { } private static int withinPercentageBounds(int value) { - if (value < 0) { - return 0; - } - return Math.min(value, 100); + return (value < 0) ? 0 : Math.min(value, 100); } /** @@ -115,8 +112,7 @@ void update(ImageProgressUpdateEvent event) { } private int updateProgress(int current, ProgressDetail detail) { - int result = withinPercentageBounds((int) ((100.0 / detail.getTotal()) * detail.getCurrent())); - return Math.max(result, current); + return Math.max(detail.asPercentage(), current); } void finish() { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/ProgressUpdateEventTests.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/ProgressUpdateEventTests.java index 063e17ffc3a5..dd43af828992 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/ProgressUpdateEventTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/ProgressUpdateEventTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -39,17 +39,21 @@ void getStatusReturnsStatus() { } @Test + @SuppressWarnings("removal") void getProgressDetailsReturnsProgressDetails() { ProgressUpdateEvent event = createEvent(); assertThat(event.getProgressDetail().getCurrent()).isOne(); assertThat(event.getProgressDetail().getTotal()).isEqualTo(2); + assertThat(event.getProgressDetail().asPercentage()).isEqualTo(50); } @Test + @SuppressWarnings("removal") void getProgressDetailsReturnsProgressDetailsForLongNumbers() { ProgressUpdateEvent event = createEvent("status", new ProgressDetail(4000000000L, 8000000000L), "progress"); - assertThat(event.getProgressDetail().getCurrent()).isEqualTo(4000000000L); - assertThat(event.getProgressDetail().getTotal()).isEqualTo(8000000000L); + assertThat(event.getProgressDetail().getCurrent()).isEqualTo(Integer.MAX_VALUE); + assertThat(event.getProgressDetail().getTotal()).isEqualTo(Integer.MAX_VALUE); + assertThat(event.getProgressDetail().asPercentage()).isEqualTo(50); } @Test @@ -59,18 +63,21 @@ void getProgressReturnsProgress() { } @Test + @SuppressWarnings("removal") void progressDetailIsEmptyWhenCurrentIsNullReturnsTrue() { ProgressDetail detail = new ProgressDetail(null, 2L); assertThat(ProgressDetail.isEmpty(detail)).isTrue(); } @Test + @SuppressWarnings("removal") void progressDetailIsEmptyWhenTotalIsNullReturnsTrue() { ProgressDetail detail = new ProgressDetail(1L, null); assertThat(ProgressDetail.isEmpty(detail)).isTrue(); } @Test + @SuppressWarnings("removal") void progressDetailIsEmptyWhenTotalAndCurrentAreNotNullReturnsFalse() { ProgressDetail detail = new ProgressDetail(1L, 2L); assertThat(ProgressDetail.isEmpty(detail)).isFalse(); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/PullUpdateEventTests.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/PullUpdateEventTests.java index 79bb5fd97bd6..7c95f9bcbd0f 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/PullUpdateEventTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/PullUpdateEventTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2024 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. @@ -30,6 +30,7 @@ class PullUpdateEventTests extends AbstractJsonTests { @Test + @SuppressWarnings("removal") void readValueWhenFullDeserializesJson() throws Exception { PullImageUpdateEvent event = getObjectMapper().readValue(getContent("pull-update-full.json"), PullImageUpdateEvent.class); @@ -37,6 +38,7 @@ void readValueWhenFullDeserializesJson() throws Exception { assertThat(event.getStatus()).isEqualTo("Extracting"); assertThat(event.getProgressDetail().getCurrent()).isEqualTo(16); assertThat(event.getProgressDetail().getTotal()).isEqualTo(32); + assertThat(event.getProgressDetail().asPercentage()).isEqualTo(50); assertThat(event.getProgress()).isEqualTo("[==================================================>] 32B/32B"); } From b340c855c031ec25b3db37bc74ad4cc47f11a549 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Mon, 2 Dec 2024 19:02:02 -0800 Subject: [PATCH 036/203] Prevent H2 console from causing early DataSource initialization Update `H2ConsoleAutoConfiguration` so that DataSource connection logging occurs outside of the `ServletRegistrationBean`. Fixes gh-43337 --- .../h2/H2ConsoleAutoConfiguration.java | 90 ++++++++++++------- .../h2/H2ConsoleAutoConfigurationTests.java | 35 +++++++- 2 files changed, 90 insertions(+), 35 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 22720348a2b4..7f2c096264f8 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-2022 the original author or authors. + * Copyright 2012-2024 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. @@ -46,6 +46,7 @@ * @author Andy Wilkinson * @author Marten Deinum * @author Stephane Nicoll + * @author Phillip Webb * @since 1.3.0 */ @AutoConfiguration(after = DataSourceAutoConfiguration.class) @@ -57,46 +58,25 @@ public class H2ConsoleAutoConfiguration { private static final Log logger = LogFactory.getLog(H2ConsoleAutoConfiguration.class); + private final H2ConsoleProperties properties; + + H2ConsoleAutoConfiguration(H2ConsoleProperties properties) { + this.properties = properties; + } + @Bean - public ServletRegistrationBean h2Console(H2ConsoleProperties properties, - ObjectProvider dataSource) { - String path = properties.getPath(); + public ServletRegistrationBean h2Console() { + String path = this.properties.getPath(); String urlMapping = path + (path.endsWith("/") ? "*" : "/*"); ServletRegistrationBean registration = new ServletRegistrationBean<>(new JakartaWebServlet(), urlMapping); - configureH2ConsoleSettings(registration, properties.getSettings()); - if (logger.isInfoEnabled()) { - withThreadContextClassLoader(getClass().getClassLoader(), () -> logDataSources(dataSource, path)); - } + configureH2ConsoleSettings(registration, this.properties.getSettings()); return registration; } - private void withThreadContextClassLoader(ClassLoader classLoader, Runnable action) { - ClassLoader previous = Thread.currentThread().getContextClassLoader(); - try { - Thread.currentThread().setContextClassLoader(classLoader); - action.run(); - } - finally { - Thread.currentThread().setContextClassLoader(previous); - } - } - - private void logDataSources(ObjectProvider dataSource, String path) { - List urls = dataSource.orderedStream().map(this::getConnectionUrl).filter(Objects::nonNull).toList(); - if (!urls.isEmpty()) { - logger.info(LogMessage.format("H2 console available at '%s'. %s available at %s", path, - (urls.size() > 1) ? "Databases" : "Database", String.join(", ", urls))); - } - } - - private String getConnectionUrl(DataSource dataSource) { - try (Connection connection = dataSource.getConnection()) { - return "'" + connection.getMetaData().getURL() + "'"; - } - catch (Exception ex) { - return null; - } + @Bean + H2ConsoleLogger h2ConsoleLogger(ObjectProvider dataSource) { + return new H2ConsoleLogger(dataSource, this.properties.getPath()); } private void configureH2ConsoleSettings(ServletRegistrationBean registration, @@ -112,4 +92,46 @@ private void configureH2ConsoleSettings(ServletRegistrationBean dataSources, String path) { + if (logger.isInfoEnabled()) { + ClassLoader classLoader = getClass().getClassLoader(); + withThreadContextClassLoader(classLoader, () -> log(getConnectionUrls(dataSources), path)); + } + } + + private void withThreadContextClassLoader(ClassLoader classLoader, Runnable action) { + ClassLoader previous = Thread.currentThread().getContextClassLoader(); + try { + Thread.currentThread().setContextClassLoader(classLoader); + action.run(); + } + finally { + Thread.currentThread().setContextClassLoader(previous); + } + } + + private List getConnectionUrls(ObjectProvider dataSources) { + return dataSources.orderedStream().map(this::getConnectionUrl).filter(Objects::nonNull).toList(); + } + + private String getConnectionUrl(DataSource dataSource) { + try (Connection connection = dataSource.getConnection()) { + return "'" + connection.getMetaData().getURL() + "'"; + } + catch (Exception ex) { + return null; + } + } + + private void log(List urls, String path) { + if (!urls.isEmpty()) { + logger.info(LogMessage.format("H2 console available at '%s'. %s available at %s", path, + (urls.size() > 1) ? "Databases" : "Database", String.join(", ", urls))); + } + } + + } + } 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 f478262c8165..d577b59baed9 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-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -30,15 +30,20 @@ import org.springframework.beans.factory.BeanCreationException; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration; import org.springframework.boot.context.properties.ConfigurationPropertiesBindException; import org.springframework.boot.context.properties.bind.BindException; import org.springframework.boot.test.context.runner.WebApplicationContextRunner; import org.springframework.boot.test.system.CapturedOutput; import org.springframework.boot.test.system.OutputCaptureExtension; import org.springframework.boot.web.servlet.ServletRegistrationBean; +import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext; +import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; +import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; +import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.BDDMockito.given; @@ -51,6 +56,7 @@ * @author Marten Deinum * @author Stephane Nicoll * @author Shraddha Yeole + * @author Phillip Webb */ class H2ConsoleAutoConfigurationTests { @@ -163,6 +169,22 @@ void h2ConsoleShouldNotFailIfDatabaseConnectionFails() { .run((context) -> assertThat(context.isRunning()).isTrue()); } + @Test + @ExtendWith(OutputCaptureExtension.class) + void dataSourceIsNotInitializedEarly(CapturedOutput output) { + new WebApplicationContextRunner(AnnotationConfigServletWebServerApplicationContext::new) + .withConfiguration(AutoConfigurations.of(H2ConsoleAutoConfiguration.class, + ServletWebServerFactoryAutoConfiguration.class)) + .withUserConfiguration(EarlyInitializationConfiguration.class) + .withPropertyValues("spring.h2.console.enabled=true", "server.port=0") + .run((context) -> { + try (Connection connection = context.getBean(DataSource.class).getConnection()) { + assertThat(output).contains("H2 console available at '/h2-console'. Database available at '" + + connection.getMetaData().getURL() + "'"); + } + }); + } + @Configuration(proxyBeanMethods = false) static class FailingDataSourceConfiguration { @@ -206,4 +228,15 @@ private DataSource mockDataSource(String url) throws SQLException { } + @Configuration(proxyBeanMethods = false) + static class EarlyInitializationConfiguration { + + @Bean + DataSource dataSource(ConfigurableApplicationContext applicationContext) { + assertThat(applicationContext.getBeanFactory().isConfigurationFrozen()).isTrue(); + return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).build(); + } + + } + } From 3e37a50b1e0835a0eb04ba1755551e1eafbc236d Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 3 Dec 2024 12:01:07 -0800 Subject: [PATCH 037/203] Fix actuator access documentation to use 'none' rather than 'disabled' Closes gh-43351 --- .../antora/modules/reference/pages/actuator/endpoints.adoc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/actuator/endpoints.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/actuator/endpoints.adoc index 9447c5830385..f59822733925 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/actuator/endpoints.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/actuator/endpoints.adoc @@ -132,15 +132,15 @@ management: access: unrestricted ---- -If you prefer access to be opt-in rather than opt-out, set the configprop:management.endpoints.access.default[] property to `disabled` and use individual endpoint `access` properties to opt back in. -The following example allows read-only access to the `loggers` endpoint and disables all other endpoints: +If you prefer access to be opt-in rather than opt-out, set the configprop:management.endpoints.access.default[] property to `none` and use individual endpoint `access` properties to opt back in. +The following example allows read-only access to the `loggers` endpoint and denies access to all other endpoints: [configprops,yaml] ---- management: endpoints: access: - default: disabled + default: none endpoint: loggers: access: read-only @@ -150,6 +150,7 @@ NOTE: Inaccessible endpoints are removed entirely from the application context. If you want to change only the technologies over which an endpoint is exposed, use the xref:actuator/endpoints.adoc#actuator.endpoints.exposing[`include` and `exclude` properties] instead. + [[actuator.endpoints.controlling-access.limiting]] === Limiting Access From 7a4e071709a502fda9f23def27f26b0049200583 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 3 Dec 2024 14:45:25 -0800 Subject: [PATCH 038/203] Polish --- .../ssl/SslAutoConfigurationTests.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ssl/SslAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ssl/SslAutoConfigurationTests.java index 87e2e0c3d1e6..87fd89f85477 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ssl/SslAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ssl/SslAutoConfigurationTests.java @@ -108,14 +108,14 @@ void sslBundlesCreatedWithCustomSslBundle() { .run((context) -> { assertThat(context).hasSingleBean(SslBundles.class); SslBundles bundles = context.getBean(SslBundles.class); - SslBundle first = bundles.getBundle("custom"); - assertThat(first).isNotNull(); - assertThat(first.getStores()).isNotNull(); - assertThat(first.getManagers()).isNotNull(); - assertThat(first.getKey().getAlias()).isEqualTo("alias1"); - assertThat(first.getKey().getPassword()).isEqualTo("secret1"); - assertThat(first.getStores().getKeyStore().getType()).isEqualTo("PKCS12"); - assertThat(first.getStores().getTrustStore().getType()).isEqualTo("PKCS12"); + SslBundle bundle = bundles.getBundle("custom"); + assertThat(bundle).isNotNull(); + assertThat(bundle.getStores()).isNotNull(); + assertThat(bundle.getManagers()).isNotNull(); + assertThat(bundle.getKey().getAlias()).isEqualTo("alias1"); + assertThat(bundle.getKey().getPassword()).isEqualTo("secret1"); + assertThat(bundle.getStores().getKeyStore().getType()).isEqualTo("PKCS12"); + assertThat(bundle.getStores().getTrustStore().getType()).isEqualTo("PKCS12"); }); } From 3ddfd62f1685decaa4687c4b062b8dad42e74baa Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 3 Dec 2024 14:46:13 -0800 Subject: [PATCH 039/203] Prefer file resolution when loading SSL content Update `SslAutoConfiguration` so that the used resource loader prefers file based resolution when paths are specified without a prefix. This restores the behavior found in Spring Boot 3.3. The `ApplicationResourceLoader` has been updated with a new `get` method that accepts a `preferFileResolution` parameter. Unfortunately, we can't directly influence the resource returned by the delegate `ResourceLoader` since we can't override `getResourceByPath(...)`. Instead we check if the returned type was likely to have been created by a call to that method. If so, we change it to a `FileSystemResource`. This approach should hopefully work with `DefaultResourceLoader` and subclasses. Fixes gh-43274 --- .../ssl/SslAutoConfiguration.java | 2 +- .../ssl/SslAutoConfigurationTests.java | 18 ++++++ .../boot/io/ApplicationResourceLoader.java | 63 +++++++++++++++++-- .../io/ApplicationResourceLoaderTests.java | 48 ++++++++++++++ 4 files changed, 126 insertions(+), 5 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ssl/SslAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ssl/SslAutoConfiguration.java index 46af4615a0e8..c3e8bf469774 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ssl/SslAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ssl/SslAutoConfiguration.java @@ -43,7 +43,7 @@ public class SslAutoConfiguration { private final SslProperties sslProperties; SslAutoConfiguration(ResourceLoader resourceLoader, SslProperties sslProperties) { - this.resourceLoader = ApplicationResourceLoader.get(resourceLoader); + this.resourceLoader = ApplicationResourceLoader.get(resourceLoader, true); this.sslProperties = sslProperties; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ssl/SslAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ssl/SslAutoConfigurationTests.java index 87fd89f85477..c810f298abb9 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ssl/SslAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ssl/SslAutoConfigurationTests.java @@ -119,6 +119,24 @@ void sslBundlesCreatedWithCustomSslBundle() { }); } + @Test + void sslBundleWithoutClassPathPrefix() { + List propertyValues = new ArrayList<>(); + String location = "src/test/resources/org/springframework/boot/autoconfigure/ssl/"; + propertyValues.add("spring.ssl.bundle.pem.test.key.alias=alias1"); + propertyValues.add("spring.ssl.bundle.pem.test.key.password=secret1"); + propertyValues.add("spring.ssl.bundle.pem.test.keystore.certificate=" + location + "rsa-cert.pem"); + propertyValues.add("spring.ssl.bundle.pem.test.keystore.keystore.private-key=" + location + "rsa-key.pem"); + propertyValues.add("spring.ssl.bundle.pem.test.truststore.certificate=" + location + "rsa-cert.pem"); + this.contextRunner.withPropertyValues(propertyValues.toArray(String[]::new)).run((context) -> { + assertThat(context).hasSingleBean(SslBundles.class); + SslBundles bundles = context.getBean(SslBundles.class); + SslBundle bundle = bundles.getBundle("test"); + assertThat(bundle.getStores().getKeyStore().getCertificate("alias1")).isNotNull(); + assertThat(bundle.getStores().getTrustStore().getCertificate("ssl")).isNotNull(); + }); + } + @Configuration @EnableConfigurationProperties(CustomSslProperties.class) public static class CustomSslBundleConfiguration { diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/io/ApplicationResourceLoader.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/io/ApplicationResourceLoader.java index 819b082a9923..de160fdaa3ff 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/io/ApplicationResourceLoader.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/io/ApplicationResourceLoader.java @@ -18,6 +18,7 @@ import java.util.List; +import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.ContextResource; import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.FileSystemResource; @@ -26,6 +27,7 @@ import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.support.SpringFactoriesLoader; import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; /** @@ -120,8 +122,25 @@ public static ResourceLoader get(ClassLoader classLoader, SpringFactoriesLoader * @since 3.4.0 */ public static ResourceLoader get(ResourceLoader resourceLoader) { + return get(resourceLoader, false); + } + + /** + * Return a {@link ResourceLoader} delegating to the given resource loader and + * supporting additional {@link ProtocolResolver ProtocolResolvers} registered in + * {@code spring.factories}. The factories file will be resolved using the default + * class loader at the time this call is made. + * @param resourceLoader the delegate resource loader + * @param preferFileResolution if file based resolution is preferred over + * {@code ServletContextResource} or {@link ClassPathResource} when no resource prefix + * is provided. + * @return a {@link ResourceLoader} instance + * @since 3.4.1 + */ + public static ResourceLoader get(ResourceLoader resourceLoader, boolean preferFileResolution) { Assert.notNull(resourceLoader, "'resourceLoader' must not be null"); - return get(resourceLoader, SpringFactoriesLoader.forDefaultResourceLocation(resourceLoader.getClassLoader())); + return get(resourceLoader, SpringFactoriesLoader.forDefaultResourceLocation(resourceLoader.getClassLoader()), + preferFileResolution); } /** @@ -135,9 +154,15 @@ public static ResourceLoader get(ResourceLoader resourceLoader) { * @since 3.4.0 */ public static ResourceLoader get(ResourceLoader resourceLoader, SpringFactoriesLoader springFactoriesLoader) { + return get(resourceLoader, springFactoriesLoader, false); + } + + private static ResourceLoader get(ResourceLoader resourceLoader, SpringFactoriesLoader springFactoriesLoader, + boolean preferFileResolution) { Assert.notNull(resourceLoader, "'resourceLoader' must not be null"); Assert.notNull(springFactoriesLoader, "'springFactoriesLoader' must not be null"); - return new ProtocolResolvingResourceLoader(resourceLoader, springFactoriesLoader.load(ProtocolResolver.class)); + return new ProtocolResolvingResourceLoader(resourceLoader, springFactoriesLoader.load(ProtocolResolver.class), + preferFileResolution); } /** @@ -185,13 +210,30 @@ public String getPathWithinContext() { */ private static class ProtocolResolvingResourceLoader implements ResourceLoader { + private static final String SERVLET_CONTEXT_RESOURCE_CLASS_NAME = "org.springframework.web.context.support.ServletContextResource"; + private final ResourceLoader resourceLoader; private final List protocolResolvers; - ProtocolResolvingResourceLoader(ResourceLoader resourceLoader, List protocolResolvers) { + private final boolean preferFileResolution; + + private Class servletContextResourceClass; + + ProtocolResolvingResourceLoader(ResourceLoader resourceLoader, List protocolResolvers, + boolean preferFileResolution) { this.resourceLoader = resourceLoader; this.protocolResolvers = protocolResolvers; + this.preferFileResolution = preferFileResolution; + this.servletContextResourceClass = resolveServletContextResourceClass( + resourceLoader.getClass().getClassLoader()); + } + + private static Class resolveServletContextResourceClass(ClassLoader classLoader) { + if (!ClassUtils.isPresent(SERVLET_CONTEXT_RESOURCE_CLASS_NAME, classLoader)) { + return null; + } + return ClassUtils.resolveClassName(SERVLET_CONTEXT_RESOURCE_CLASS_NAME, classLoader); } @Override @@ -204,7 +246,20 @@ public Resource getResource(String location) { } } } - return this.resourceLoader.getResource(location); + Resource resource = this.resourceLoader.getResource(location); + if (this.preferFileResolution + && (isClassPathResourceByPath(location, resource) || isServletResource(resource))) { + resource = new ApplicationResource(location); + } + return resource; + } + + private boolean isClassPathResourceByPath(String location, Resource resource) { + return (resource instanceof ClassPathResource) && !location.startsWith(CLASSPATH_URL_PREFIX); + } + + private boolean isServletResource(Resource resource) { + return this.servletContextResourceClass != null && this.servletContextResourceClass.isInstance(resource); } @Override diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/io/ApplicationResourceLoaderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/io/ApplicationResourceLoaderTests.java index 0384f7cfcc14..124147329512 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/io/ApplicationResourceLoaderTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/io/ApplicationResourceLoaderTests.java @@ -24,13 +24,19 @@ import java.util.Enumeration; import java.util.function.UnaryOperator; +import jakarta.servlet.ServletContext; import org.junit.jupiter.api.Test; import org.springframework.core.io.ByteArrayResource; +import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.DefaultResourceLoader; +import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.support.SpringFactoriesLoader; +import org.springframework.mock.web.MockServletContext; +import org.springframework.web.context.support.ServletContextResource; +import org.springframework.web.context.support.ServletContextResourceLoader; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; @@ -152,6 +158,48 @@ void getResourceWhenPathIsNull() { .withMessage("Location must not be null"); } + @Test + void getResourceWithPreferFileResolutionWhenFullPathWithClassPathResource() throws Exception { + File file = new File("src/main/resources/a-file"); + ResourceLoader loader = ApplicationResourceLoader.get(new DefaultResourceLoader(), true); + Resource resource = loader.getResource(file.getAbsolutePath()); + assertThat(resource).isInstanceOf(FileSystemResource.class); + assertThat(resource.getFile().getAbsoluteFile()).isEqualTo(file.getAbsoluteFile()); + ResourceLoader regularLoader = ApplicationResourceLoader.get(new DefaultResourceLoader(), false); + assertThat(regularLoader.getResource(file.getAbsolutePath())).isInstanceOf(ClassPathResource.class); + } + + @Test + void getResourceWithPreferFileResolutionWhenRelativePathWithClassPathResource() throws Exception { + ResourceLoader loader = ApplicationResourceLoader.get(new DefaultResourceLoader(), true); + Resource resource = loader.getResource("src/main/resources/a-file"); + assertThat(resource).isInstanceOf(FileSystemResource.class); + assertThat(resource.getFile().getAbsoluteFile()) + .isEqualTo(new File("src/main/resources/a-file").getAbsoluteFile()); + ResourceLoader regularLoader = ApplicationResourceLoader.get(new DefaultResourceLoader(), false); + assertThat(regularLoader.getResource("src/main/resources/a-file")).isInstanceOf(ClassPathResource.class); + } + + @Test + void getResourceWithPreferFileResolutionWhenExplicitClassPathPrefix() { + ResourceLoader loader = ApplicationResourceLoader.get(new DefaultResourceLoader(), true); + Resource resource = loader.getResource("classpath:a-file"); + assertThat(resource).isInstanceOf(ClassPathResource.class); + } + + @Test + void getResourceWithPreferFileResolutionWhenPathWithServletContextResource() throws Exception { + ServletContext servletContext = new MockServletContext(); + ServletContextResourceLoader servletContextResourceLoader = new ServletContextResourceLoader(servletContext); + ResourceLoader loader = ApplicationResourceLoader.get(servletContextResourceLoader, true); + Resource resource = loader.getResource("src/main/resources/a-file"); + assertThat(resource).isInstanceOf(FileSystemResource.class); + assertThat(resource.getFile().getAbsoluteFile()) + .isEqualTo(new File("src/main/resources/a-file").getAbsoluteFile()); + ResourceLoader regularLoader = ApplicationResourceLoader.get(servletContextResourceLoader, false); + assertThat(regularLoader.getResource("src/main/resources/a-file")).isInstanceOf(ServletContextResource.class); + } + @Test void getClassLoaderReturnsDelegateClassLoader() { ClassLoader classLoader = new TestClassLoader(this::useTestProtocolResolversFactories); From 4265a0bcc2a71d14443126bb285555c038aae15e Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 3 Dec 2024 18:49:59 -0800 Subject: [PATCH 040/203] Reset `Startables` COUNTER when testing parallel startup Closes gh-43369 --- .../spring-boot-testcontainers/build.gradle | 4 ++ .../lifecycle/ResetStartablesExtension.java | 60 +++++++++++++++++++ ...hImportTestcontainersIntegrationTests.java | 2 +- 3 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/lifecycle/ResetStartablesExtension.java diff --git a/spring-boot-project/spring-boot-testcontainers/build.gradle b/spring-boot-project/spring-boot-testcontainers/build.gradle index 091fcf0462c4..1fa86932aacd 100644 --- a/spring-boot-project/spring-boot-testcontainers/build.gradle +++ b/spring-boot-project/spring-boot-testcontainers/build.gradle @@ -96,3 +96,7 @@ dependencies { testImplementation("org.springframework.pulsar:spring-pulsar") testImplementation("org.testcontainers:junit-jupiter") } + +dockerTest { + jvmArgs += "--add-opens=java.base/java.util.concurrent=ALL-UNNAMED" +} diff --git a/spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/lifecycle/ResetStartablesExtension.java b/spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/lifecycle/ResetStartablesExtension.java new file mode 100644 index 000000000000..08fe0fe0edad --- /dev/null +++ b/spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/lifecycle/ResetStartablesExtension.java @@ -0,0 +1,60 @@ +/* + * Copyright 2012-2024 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.testcontainers.lifecycle; + +import java.lang.reflect.InaccessibleObjectException; +import java.util.concurrent.atomic.AtomicLong; + +import org.junit.jupiter.api.extension.AfterEachCallback; +import org.junit.jupiter.api.extension.BeforeEachCallback; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.testcontainers.lifecycle.Startables; + +import org.springframework.test.util.ReflectionTestUtils; + +/** + * JUnit extension used by reset startables. + * + * @author Phillip Webb + */ +class ResetStartablesExtension implements BeforeEachCallback, AfterEachCallback { + + @Override + public void afterEach(ExtensionContext context) throws Exception { + reset(); + } + + @Override + public void beforeEach(ExtensionContext context) throws Exception { + reset(); + } + + private void reset() { + try { + Object executor = ReflectionTestUtils.getField(Startables.class, "EXECUTOR"); + Object threadFactory = ReflectionTestUtils.getField(executor, "threadFactory"); + AtomicLong counter = (AtomicLong) ReflectionTestUtils.getField(threadFactory, "COUNTER"); + counter.set(0); + } + catch (InaccessibleObjectException ex) { + throw new IllegalStateException( + "Unable to reset field. Please run with '--add-opens=java.base/java.util.concurrent=ALL-UNNAMED'", + ex); + } + } + +} diff --git a/spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/lifecycle/TestContainersParallelStartupWithImportTestcontainersIntegrationTests.java b/spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/lifecycle/TestContainersParallelStartupWithImportTestcontainersIntegrationTests.java index e3a9cfb57fbb..adbcbb900e06 100644 --- a/spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/lifecycle/TestContainersParallelStartupWithImportTestcontainersIntegrationTests.java +++ b/spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/lifecycle/TestContainersParallelStartupWithImportTestcontainersIntegrationTests.java @@ -40,7 +40,7 @@ @ExtendWith(SpringExtension.class) @TestPropertySource(properties = "spring.testcontainers.beans.startup=parallel") @DisabledIfDockerUnavailable -@ExtendWith(OutputCaptureExtension.class) +@ExtendWith({ OutputCaptureExtension.class, ResetStartablesExtension.class }) @ImportTestcontainers(Containers.class) class TestContainersParallelStartupWithImportTestcontainersIntegrationTests { From 75a3722ee4f407caafac2dd0fcb2750dc27a0e92 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 3 Dec 2024 20:03:20 -0800 Subject: [PATCH 041/203] Add more anchor redirects See gh-43367 --- .../src/docs/antora/modules/ROOT/pages/redirect.adoc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/ROOT/pages/redirect.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/ROOT/pages/redirect.adoc index 884612ffdf8b..0ca5cb524576 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/ROOT/pages/redirect.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/ROOT/pages/redirect.adoc @@ -24,7 +24,9 @@ * xref:specification:executable-jar/index.adoc[executable-jar] * xref:appendix:dependency-versions/index.adoc[dependency-versions] * xref:community.adoc[#getting-help] +* xref:community.adoc[#documentation.getting-help] * xref:documentation.adoc[#documentation] +* xref:documentation.adoc[#documentation.about] * xref:index.adoc[#getting-started] * xref:upgrading.adoc[#upgrading] * xref:reference:using/index.adoc#using[#using] @@ -1615,3 +1617,11 @@ * xref:tutorial:first-application/index.adoc#getting-started.first-application.run[#getting-started.first-application.run] * xref:tutorial:first-application/index.adoc#getting-started.first-application.run.gradle[#getting-started.first-application.run.gradle] * xref:tutorial:first-application/index.adoc#getting-started.first-application.run.maven[#getting-started.first-application.run.maven] +* xref:reference:io/caching.adoc#io.caching.provider.jcache[#features.caching.provider.ehcache2] +* xref:reference:features/external-config.adoc#features.external-config.files.importing-extensionless[#features.external-config.file.importing-extensionless] +* xref:reference:using/build-systems.adoc#using.build-systems.maven[#build-tool-plugins.maven] +* xref:reference:using/build-systems.adoc#using.build-systems.gradle[#build-tool-plugins.gradle] +* xref:reference:messaging/amqp.adoc#messaging.amqp.rabbitmq[#messaging.amqp.rabbit] +* xref:reference:data/nosql.adoc#data.nosql.elasticsearch.connecting-using-rest[#data.nosql.elasticsearch.connecting-using-reactive-rest] +* xref:index.adoc[#getting-started.introducing-spring-boot] +* xref:index.adoc[#spring-boot-reference-documentation] From 709cd91b3e7f54cf4243cd0835c41c090bf1539a Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 3 Dec 2024 20:14:19 -0800 Subject: [PATCH 042/203] Add legacy anchor redirects Add anchor redirects previously covered by the `anchor-rewrite.properties` file. See gh-43367 --- .../antora/modules/ROOT/pages/redirect.adoc | 726 ++++++++++++++++++ 1 file changed, 726 insertions(+) diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/ROOT/pages/redirect.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/ROOT/pages/redirect.adoc index 0ca5cb524576..6ec633abbe4c 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/ROOT/pages/redirect.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/ROOT/pages/redirect.adoc @@ -1625,3 +1625,729 @@ * xref:reference:data/nosql.adoc#data.nosql.elasticsearch.connecting-using-rest[#data.nosql.elasticsearch.connecting-using-reactive-rest] * xref:index.adoc[#getting-started.introducing-spring-boot] * xref:index.adoc[#spring-boot-reference-documentation] +* xref:appendix:application-properties/index.adoc#appendix.application-properties.actuator[#common-application-properties-actuator] +* xref:reference:actuator/http-exchanges.adoc#actuator.http-exchanges[#actuator.tracing] +* xref:reference:actuator/http-exchanges.adoc#actuator.http-exchanges.custom[#actuator.tracing.custom] +* xref:appendix:application-properties/index.adoc#appendix.application-properties[#common-application-properties] +* xref:appendix:application-properties/index.adoc#appendix.application-properties.cache[#common-application-properties-cache] +* xref:appendix:application-properties/index.adoc#appendix.application-properties.core[#core-properties] +* xref:appendix:application-properties/index.adoc#appendix.application-properties.data[#data-properties] +* xref:appendix:application-properties/index.adoc#appendix.application-properties.data-migration[#data-migration-properties] +* xref:appendix:application-properties/index.adoc#appendix.application-properties.devtools[#devtools-properties] +* xref:appendix:application-properties/index.adoc#appendix.application-properties.integration[#integration-properties] +* xref:appendix:application-properties/index.adoc#appendix.application-properties.json[#json-properties] +* xref:appendix:application-properties/index.adoc#appendix.application-properties.mail[#mail-properties] +* xref:appendix:application-properties/index.adoc#appendix.application-properties.rsocket[#rsocket-properties] +* xref:appendix:application-properties/index.adoc#appendix.application-properties.security[#security-properties] +* xref:appendix:application-properties/index.adoc#appendix.application-properties.server[#server-properties] +* xref:appendix:application-properties/index.adoc#appendix.application-properties.templating[#templating-properties] +* xref:appendix:application-properties/index.adoc#appendix.application-properties.testing[#testing-properties] +* xref:appendix:application-properties/index.adoc#appendix.application-properties.transaction[#transaction-properties] +* xref:appendix:application-properties/index.adoc#appendix.application-properties.web[#web-properties] +* xref:appendix:auto-configuration-classes/index.adoc#appendix.auto-configuration-classes[#auto-configuration-classes] +* xref:appendix:auto-configuration-classes/actuator.adoc#appendix.auto-configuration-classes.actuator[#auto-configuration-classes.actuator] +* xref:appendix:auto-configuration-classes/core.adoc#appendix.auto-configuration-classes.core[#auto-configuration-classes.core] +* xref:ROOT:documentation.adoc#documentation[#boot-documentation] +* xref:documentation.adoc[#boot-documentation-about] +* xref:ROOT:documentation.adoc#documentation.advanced[#boot-documentation-advanced] +* xref:ROOT:documentation.adoc#documentation.first-steps[#boot-documentation-first-steps] +* xref:community.adoc[#boot-documentation-getting-help] +* xref:ROOT:documentation.adoc#documentation.features[#boot-documentation-learning] +* xref:ROOT:documentation.adoc#documentation.actuator[#boot-documentation-production] +* xref:ROOT:documentation.adoc#documentation.upgrading[#boot-documentation-upgrading] +* xref:ROOT:documentation.adoc#documentation.using[#boot-documentation-workingwith] +* xref:reference:features/index.adoc#features[#boot-features] +* xref:reference:messaging/jms.adoc#messaging.jms.activemq[#features.messaging.jms.activemq] +* xref:reference:features/profiles.adoc#features.profiles.adding-active-profiles[#boot-features-adding-active-profiles] +* xref:reference:messaging/amqp.adoc#messaging.amqp[#features.messaging.amqp] +* xref:reference:features/spring-application.adoc#features.spring-application.admin[#boot-features-application-admin] +* xref:reference:features/spring-application.adoc#features.spring-application.application-arguments[#boot-features-application-arguments] +* xref:reference:features/spring-application.adoc#features.spring-application.application-availability[#boot-features-application-availability] +* xref:reference:features/spring-application.adoc#features.spring-application.application-availability.liveness[#boot-features-application-availability-liveness-state] +* xref:reference:features/spring-application.adoc#features.spring-application.application-availability.managing[#boot-features-application-availability-managing] +* xref:reference:features/spring-application.adoc#features.spring-application.application-availability.readiness[#boot-features-application-availability-readiness-state] +* xref:reference:features/spring-application.adoc#features.spring-application.application-events-and-listeners[#boot-features-application-events-and-listeners] +* xref:reference:features/spring-application.adoc#features.spring-application.application-exit[#boot-features-application-exit] +* xref:reference:features/spring-application.adoc#features.spring-application.startup-tracking[#boot-features-application-startup-tracking] +* xref:reference:messaging/jms.adoc#messaging.jms.artemis[#features.messaging.jms.artemis] +* xref:reference:features/spring-application.adoc#features.spring-application.banner[#boot-features-banner] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.bean-conditions[#boot-features-bean-conditions] +* xref:reference:io/caching.adoc#io.caching[#features.caching] +* xref:reference:io/caching.adoc#io.caching.provider[#features.caching.provider] +* xref:reference:io/caching.adoc#io.caching.provider.caffeine[#features.caching.provider.caffeine] +* xref:reference:io/caching.adoc#io.caching.provider.couchbase[#features.caching.provider.couchbase] +* xref:reference:io/caching.adoc#io.caching.provider.jcache[#features.caching.provider.jcache] +* xref:reference:io/caching.adoc#io.caching.provider.generic[#features.caching.provider.generic] +* xref:reference:io/caching.adoc#io.caching.provider.hazelcast[#features.caching.provider.hazelcast] +* xref:reference:io/caching.adoc#io.caching.provider.infinispan[#features.caching.provider.infinispan] +* xref:reference:io/caching.adoc#io.caching.provider.none[#features.caching.provider.none] +* xref:reference:io/caching.adoc#io.caching.provider.redis[#features.caching.provider.redis] +* xref:reference:io/caching.adoc#io.caching.provider.simple[#features.caching.provider.simple] +* xref:reference:data/nosql.adoc#data.nosql.cassandra[#features.nosql.cassandra] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.class-conditions[#boot-features-class-conditions] +* xref:reference:features/spring-application.adoc#features.spring-application.command-line-runner[#boot-features-command-line-runner] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations[#boot-features-condition-annotations] +* xref:reference:testing/test-utilities.adoc#testing.utilities.config-data-application-context-initializer[#boot-features-configfileapplicationcontextinitializer-test-utility] +* xref:reference:data/sql.adoc#data.sql.datasource[#features.sql.datasource] +* xref:reference:data/sql.adoc#data.sql.datasource.production[#features.sql.datasource.production] +* xref:reference:data/sql.adoc#data.sql.datasource.configuration[#features.sql.datasource.configuration] +* xref:reference:data/sql.adoc#data.sql.datasource.connection-pool[#features.sql.datasource.connection-pool] +* xref:reference:data/sql.adoc#data.sql.datasource.jndi[#features.sql.datasource.jndi] +* xref:reference:data/nosql.adoc#data.nosql.cassandra.connecting[#features.nosql.cassandra.connecting] +* xref:reference:data/nosql.adoc#data.nosql.couchbase.connecting[#features.nosql.couchbase.connecting] +* xref:reference:data/nosql.adoc#data.nosql.elasticsearch[#features.nosql.elasticsearch] +* xref:reference:data/nosql.adoc#data.nosql.elasticsearch.connecting-using-rest[#features.nosql.elasticsearch.connecting-using-rest] +* xref:reference:data/nosql.adoc#data.nosql.elasticsearch.connecting-using-spring-data[#features.nosql.elasticsearch.connecting-using-spring-data] +* xref:reference:data/nosql.adoc#data.nosql.influxdb.connecting[#features.nosql.influxdb.connecting] +* xref:reference:data/nosql.adoc#data.nosql.mongodb.connecting[#features.nosql.mongodb.connecting] +* xref:reference:data/nosql.adoc#data.nosql.neo4j.connecting[#features.nosql.neo4j.connecting] +* xref:reference:data/nosql.adoc#data.nosql.redis.connecting[#features.nosql.redis.connecting] +* xref:reference:packaging/container-images/efficient-images.adoc#packaging.container-images.efficient-images[#features.container-images.building] +* xref:reference:packaging/container-images/cloud-native-buildpacks.adoc#packaging.container-images.buildpacks[#features.container-images.building.buildpacks] +* xref:reference:packaging/container-images/dockerfiles.adoc#packaging.container-images.dockerfiles[#features.container-images.building.dockerfiles] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.cors[#features.developing-web-applications.spring-mvc.cors] +* xref:reference:data/nosql.adoc#data.nosql.couchbase[#features.nosql.couchbase] +* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.creating-and-dropping[#features.sql.jpa-and-spring-data.creating-and-dropping] +* xref:reference:features/logging.adoc#features.logging.custom-log-configuration[#boot-features-custom-log-configuration] +* xref:reference:features/logging.adoc#features.logging.log-groups[#boot-features-custom-log-groups] +* xref:reference:features/logging.adoc#features.logging.log-levels[#boot-features-custom-log-levels] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.custom-starter[#boot-features-custom-starter] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.custom-starter.configuration-keys[#boot-features-custom-starter-configuration-keys] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.custom-starter.autoconfigure-module[#boot-features-custom-starter-module-autoconfigure] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.custom-starter.starter-module[#boot-features-custom-starter-module-starter] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.custom-starter.naming[#boot-features-custom-starter-naming] +* xref:reference:web/servlet.adoc#web.servlet.embedded-container.customizing.direct[#features.developing-web-applications.embedded-container.customizing.direct] +* xref:reference:web/servlet.adoc#web.servlet.embedded-container.customizing[#features.developing-web-applications.embedded-container.customizing] +* xref:reference:features/spring-application.adoc#features.spring-application.customizing-spring-application[#boot-features-customizing-spring-application] +* xref:reference:data/sql.adoc#data.sql.jdbc[#features.sql.jdbc] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration[#boot-features-developing-auto-configuration] +* xref:reference:web/index.adoc#web[#features.developing-web-applications] +* xref:reference:io/email.adoc#io.email[#features.email] +* xref:reference:web/servlet.adoc#web.servlet.embedded-container[#features.developing-web-applications.embedded-container] +* xref:reference:web/servlet.adoc#web.servlet.embedded-container.application-context[#features.developing-web-applications.embedded-container.application-context] +* xref:reference:web/servlet.adoc#web.servlet.embedded-container.context-initializer[#features.developing-web-applications.embedded-container.context-initializer] +* xref:reference:web/servlet.adoc#web.servlet.embedded-container.servlets-filters-listeners[#features.developing-web-applications.embedded-container.servlets-filters-listeners] +* xref:reference:web/servlet.adoc#web.servlet.embedded-container.servlets-filters-listeners.beans[#features.developing-web-applications.embedded-container.servlets-filters-listeners.beans] +* xref:reference:web/servlet.adoc#web.servlet.embedded-container.context-initializer.scanning[#features.developing-web-applications.embedded-container.context-initializer.scanning] +* xref:reference:data/sql.adoc#data.sql.datasource.embedded[#features.sql.datasource.embedded] +* xref:reference:messaging/kafka.adoc#messaging.kafka.embedded[#features.messaging.kafka.embedded] +* xref:reference:features/external-config.adoc#features.external-config.encrypting[#boot-features-encrypting-properties] +* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.entity-classes[#features.sql.jpa-and-spring-data.entity-classes] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.error-handling[#features.developing-web-applications.spring-mvc.error-handling] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.error-handling.error-pages[#features.developing-web-applications.spring-mvc.error-handling.error-pages] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.error-handling.error-pages-without-spring-mvc[#features.developing-web-applications.spring-mvc.error-handling.error-pages-without-spring-mvc] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.error-handling.in-a-war-deployment[#features.developing-web-applications.spring-mvc.error-handling.in-a-war-deployment] +* xref:reference:features/external-config.adoc#features.external-config[#boot-features-external-config] +* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.third-party-configuration[#boot-features-external-config-3rd-party-configuration] +* xref:reference:features/external-config.adoc#features.external-config.application-json[#boot-features-external-config-application-json] +* xref:reference:features/external-config.adoc#features.external-config.files[#boot-features-external-config-files] +* xref:reference:features/external-config.adoc#features.external-config.command-line-args[#boot-features-external-config-command-line-args] +* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.merging-complex-types[#boot-features-external-config-complex-type-merge] +* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.constructor-binding[#boot-features-external-config-constructor-binding] +* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.conversion[#boot-features-external-config-conversion] +* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.conversion.data-sizes[#boot-features-external-config-conversion-datasize] +* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.conversion.durations[#boot-features-external-config-conversion-duration] +* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.conversion.periods[#boot-features-external-config-conversion-period] +* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.enabling-annotated-types[#boot-features-external-config-enabling] +* xref:reference:features/external-config.adoc#features.external-config.yaml.directly-loading[#boot-features-external-config-loading-yaml] +* xref:reference:features/external-config.adoc#features.external-config.files.activation-properties[#boot-features-external-config-file-activation-properties] +* xref:reference:features/external-config.adoc#features.external-config.files.configtree[#boot-features-external-config-files-configtree] +* xref:reference:features/external-config.adoc#features.external-config.files.importing[#boot-features-external-config-files-importing] +* xref:reference:features/external-config.adoc#features.external-config.files.importing-extensionless[#boot-features-external-config-files-importing-extensionless] +* xref:reference:features/external-config.adoc#features.external-config.files.multi-document[#boot-features-external-config-files-multi-document] +* xref:reference:features/external-config.adoc#features.external-config.files.profile-specific[#boot-features-external-config-files-profile-specific] +* xref:reference:features/external-config.adoc#features.external-config.files.wildcard-locations[#boot-features-external-config-files-wildcards] +* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.java-bean-binding[#boot-features-external-config-java-bean-binding] +* xref:reference:features/external-config.adoc#features.external-config.files.optional-prefix[#boot-features-external-config-optional-prefix] +* xref:reference:features/external-config.adoc#features.external-config.files.property-placeholders[#boot-features-external-config-placeholders-in-properties] +* xref:reference:features/external-config.adoc#features.external-config.random-values[#boot-features-external-config-random-values] +* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.relaxed-binding[#boot-features-external-config-relaxed-binding] +* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.relaxed-binding.environment-variables[#boot-features-external-config-relaxed-binding-from-environment-variables] +* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.relaxed-binding.maps[#boot-features-external-config-relaxed-binding-maps] +* xref:reference:features/external-config.adoc#features.external-config.system-environment[#boot-features-external-config-system-environment] +* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties[#boot-features-external-config-typesafe-configuration-properties] +* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.using-annotated-types[#boot-features-external-config-using] +* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.validation[#boot-features-external-config-validation] +* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.vs-value-annotation[#boot-features-external-config-vs-value] +* xref:reference:features/external-config.adoc#features.external-config.yaml[#boot-features-external-config-yaml] +* xref:reference:features/external-config.adoc#features.external-config.yaml.mapping-to-properties[#boot-features-external-config-yaml-to-properties] +* xref:reference:features/spring-application.adoc#features.spring-application.fluent-builder-api[#boot-features-fluent-builder-api] +* xref:reference:web/graceful-shutdown.adoc#web.graceful-shutdown[#features.graceful-shutdown] +* xref:reference:io/hazelcast.adoc#io.hazelcast[#features.hazelcast] +* xref:reference:data/nosql.adoc#data.nosql.influxdb[#features.nosql.influxdb] +* xref:reference:messaging/spring-integration.adoc#messaging.spring-integration[#features.spring-integration] +* xref:reference:features/internationalization.adoc#features.internationalization[#boot-features-internationalization] +* xref:reference:web/servlet.adoc#web.servlet.jersey[#features.developing-web-applications.jersey] +* xref:reference:messaging/jms.adoc#messaging.jms[#features.messaging.jms] +* xref:reference:messaging/jms.adoc#messaging.jms.jndi[#features.messaging.jms.jndi] +* xref:reference:actuator/jmx.adoc#actuator.jmx[#production-ready-jmx] +* xref:reference:data/sql.adoc#data.sql.jooq[#features.sql.jooq] +* xref:reference:data/sql.adoc#data.sql.jooq.codegen[#features.sql.jooq.codegen] +* xref:reference:data/sql.adoc#data.sql.jooq.customizing[#features.sql.jooq.customizing] +* xref:reference:data/sql.adoc#data.sql.jooq.dslcontext[#features.sql.jooq.dslcontext] +* xref:reference:data/sql.adoc#data.sql.jooq.sqldialect[#features.sql.jooq.sqldialect] +* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data[#features.sql.jpa-and-spring-data] +* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.open-entity-manager-in-view[#features.sql.jpa-and-spring-data.open-entity-manager-in-view] +* xref:reference:features/json.adoc#features.json[#boot-features-json] +* xref:reference:features/json.adoc#features.json.jackson.custom-serializers-and-deserializers[#web.servlet.spring-mvc.json] +* xref:reference:features/json.adoc#features.json.gson[#boot-features-json-gson] +* xref:reference:features/json.adoc#features.json.jackson[#boot-features-json-jackson] +* xref:reference:features/json.adoc#features.json.json-b[#boot-features-json-json-b] +* xref:reference:web/servlet.adoc#web.servlet.embedded-container.jsp-limitations[#features.developing-web-applications.embedded-container.jsp-limitations] +* xref:reference:io/jta.adoc#io.jta[#features.jta] +* xref:reference:io/jta.adoc#io.jta.jakartaee[#features.jta.javaee] +* xref:reference:io/jta.adoc#io.jta.mixing-xa-and-non-xa-connections[#features.jta.mixing-xa-and-non-xa-connections] +* xref:reference:io/jta.adoc#io.jta.supporting-embedded-transaction-manager[#features.jta.supporting-alternative-embedded-transaction-manager] +* xref:reference:messaging/kafka.adoc#messaging.kafka[#features.messaging.kafka] +* xref:reference:messaging/kafka.adoc#messaging.kafka.additional-properties[#features.messaging.kafka.additional-properties] +* xref:reference:messaging/kafka.adoc#messaging.kafka.receiving[#features.messaging.kafka.receiving] +* xref:reference:messaging/kafka.adoc#messaging.kafka.sending[#features.messaging.kafka.sending] +* xref:reference:messaging/kafka.adoc#messaging.kafka.streams[#features.messaging.kafka.streams] +* xref:reference:features/kotlin.adoc#features.kotlin[#boot-features-kotlin] +* xref:reference:features/kotlin.adoc#features.kotlin.api[#boot-features-kotlin-api] +* xref:reference:features/kotlin.adoc#features.kotlin.api.extensions[#boot-features-kotlin-api-extensions] +* xref:reference:features/kotlin.adoc#features.kotlin.api.run-application[#boot-features-kotlin-api-runapplication] +* xref:reference:features/kotlin.adoc#features.kotlin.configuration-properties[#boot-features-kotlin-configuration-properties] +* xref:reference:features/kotlin.adoc#features.kotlin.dependency-management[#boot-features-kotlin-dependency-management] +* xref:reference:features/kotlin.adoc#features.kotlin.null-safety[#boot-features-kotlin-null-safety] +* xref:reference:features/kotlin.adoc#features.kotlin.requirements[#boot-features-kotlin-requirements] +* xref:reference:features/kotlin.adoc#features.kotlin.resources[#boot-features-kotlin-resources] +* xref:reference:features/kotlin.adoc#features.kotlin.resources.examples[#boot-features-kotlin-resources-examples] +* xref:reference:features/kotlin.adoc#features.kotlin.resources.further-reading[#boot-features-kotlin-resources-further-reading] +* xref:reference:features/kotlin.adoc#features.kotlin.testing[#boot-features-kotlin-testing] +* xref:reference:features/spring-application.adoc#features.spring-application.lazy-initialization[#boot-features-lazy-initialization] +* xref:reference:data/nosql.adoc#data.nosql.ldap[#features.nosql.ldap] +* xref:reference:data/nosql.adoc#data.nosql.ldap.connecting[#features.nosql.ldap.connecting] +* xref:reference:data/nosql.adoc#data.nosql.ldap.embedded[#features.nosql.ldap.embedded] +* xref:reference:data/nosql.adoc#data.nosql.ldap.repositories[#features.nosql.ldap.repositories] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.locating-auto-configuration-candidates[#boot-features-locating-auto-configuration-candidates] +* xref:reference:features/logging.adoc#features.logging.shutdown-hook[#boot-features-log-shutdown-hook] +* xref:reference:features/logging.adoc#features.logging.logback-extensions.environment-properties[#boot-features-logback-environment-properties] +* xref:reference:features/logging.adoc#features.logging.logback-extensions[#boot-features-logback-extensions] +* xref:reference:features/logging.adoc#features.logging.logback-extensions.profile-specific[#boot-features-logback-extensions-profile-specific] +* xref:reference:features/logging.adoc#features.logging[#boot-features-logging] +* xref:reference:features/logging.adoc#features.logging.console-output.color-coded[#boot-features-logging-color-coded-output] +* xref:reference:features/logging.adoc#features.logging.console-output[#boot-features-logging-console-output] +* xref:reference:features/logging.adoc#features.logging.file-output[#boot-features-logging-file-output] +* xref:reference:features/logging.adoc#features.logging.file-rotation[#boot-features-logging-file-rotation] +* xref:reference:features/logging.adoc#features.logging.log-format[#boot-features-logging-format] +* xref:reference:messaging/index.adoc#messaging[#features.messaging] +* xref:reference:data/nosql.adoc#data.nosql.mongodb.template[#features.nosql.mongodb.template] +* xref:reference:data/nosql.adoc#data.nosql.mongodb[#features.nosql.mongodb] +* xref:reference:data/nosql.adoc#data.nosql.neo4j[#features.nosql.neo4j] +* xref:reference:data/nosql.adoc#data.nosql[#features.nosql] +* xref:reference:testing/test-utilities.adoc#testing.utilities.output-capture[#boot-features-output-capture-test-utility] +* xref:reference:features/profiles.adoc#features.profiles.profile-specific-configuration-files[#boot-features-profile-specific-configuration] +* xref:reference:features/profiles.adoc#features.profiles[#boot-features-profiles] +* xref:reference:features/profiles.adoc#features.profiles.groups[#boot-features-profiles-groups] +* xref:reference:web/servlet.adoc#web.servlet.embedded-container.customizing.programmatic[#features.developing-web-applications.embedded-container.customizing.programmatic] +* xref:reference:features/profiles.adoc#features.profiles.programmatically-setting-profiles[#boot-features-programmatically-setting-profiles] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.property-conditions[#boot-features-property-conditions] +* xref:reference:io/quartz.adoc#io.quartz[#features.quartz] +* xref:reference:data/sql.adoc#data.sql.r2dbc[#features.sql.r2dbc] +* xref:reference:data/sql.adoc#data.sql.r2dbc.embedded[#features.sql.r2dbc.embedded] +* xref:reference:data/sql.adoc#data.sql.r2dbc.using-database-client[#features.sql.r2dbc.using-database-client] +* xref:reference:messaging/amqp.adoc#messaging.amqp.rabbitmq[#features.messaging.amqp.rabbit] +* xref:reference:web/reactive.adoc#web.reactive.reactive-server[#features.developing-web-applications.reactive-server] +* xref:reference:web/reactive.adoc#web.reactive.reactive-server-resources-configuration[#features.developing-web-applications.reactive-server-resources-configuration] +* xref:reference:data/nosql.adoc#data.nosql.redis[#features.nosql.redis] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.resource-conditions[#boot-features-resource-conditions] +* xref:reference:testing/test-utilities.adoc#testing.utilities.test-rest-template[#boot-features-rest-templates-test-utility] +* xref:reference:io/rest-client.adoc#io.rest-client.resttemplate[#features.resttemplate] +* xref:reference:io/rest-client.adoc#io.rest-client.resttemplate.customization[#features.resttemplate.customization] +* xref:reference:messaging/rsocket.adoc#messaging.rsocket[#features.rsocket] +* xref:reference:messaging/rsocket.adoc#messaging.rsocket.messaging[#features.rsocket.messaging] +* xref:reference:messaging/rsocket.adoc#messaging.rsocket.requester[#features.rsocket.requester] +* xref:reference:messaging/rsocket.adoc#messaging.rsocket.server-auto-configuration[#features.rsocket.server-auto-configuration] +* xref:reference:messaging/rsocket.adoc#messaging.rsocket.strategies-auto-configuration[#features.rsocket.strategies-auto-configuration] +* xref:reference:web/spring-security.adoc#web.security[#features.security] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.security[#production-ready-endpoints-security] +* xref:reference:web/spring-security.adoc#web.security.oauth2.authorization-server[#features.security.authorization-server] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.security.csrf[#features.security.actuator.csrf] +* xref:reference:web/spring-security.adoc#web.security.spring-mvc[#features.security.spring-mvc] +* xref:reference:web/spring-security.adoc#web.security.oauth2[#features.security.oauth2] +* xref:reference:web/spring-security.adoc#web.security.oauth2.client[#features.security.oauth2.client] +* xref:reference:web/spring-security.adoc#web.security.oauth2.client.common-providers[#features.security.oauth2.client.common-providers] +* xref:reference:web/spring-security.adoc#web.security.oauth2.server[#features.security.oauth2.server] +* xref:reference:web/spring-security.adoc#web.security.saml2[#features.security.saml2] +* xref:reference:web/spring-security.adoc#web.security.saml2.relying-party[#features.security.saml2.relying-party] +* xref:reference:web/spring-security.adoc#web.security.spring-webflux[#features.security.spring-webflux] +* xref:reference:web/spring-session.adoc#web.spring-session[#features.spring-session] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.spel-conditions[#boot-features-spel-conditions] +* xref:reference:features/spring-application.adoc#features.spring-application[#boot-features-spring-application] +* xref:reference:data/nosql.adoc#data.nosql.cassandra.repositories[#features.nosql.cassandra.repositories] +* xref:reference:data/nosql.adoc#data.nosql.couchbase.repositories[#features.nosql.couchbase.repositories] +* xref:reference:data/nosql.adoc#data.nosql.elasticsearch.repositories[#features.nosql.elasticsearch.repositories] +* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.repositories[#features.sql.jpa-and-spring-data.repositories] +* xref:reference:data/nosql.adoc#data.nosql.mongodb.repositories[#features.nosql.mongodb.repositories] +* xref:reference:data/nosql.adoc#data.nosql.neo4j.repositories[#features.nosql.neo4j.repositories] +* xref:reference:data/sql.adoc#data.sql.r2dbc.repositories[#features.sql.r2dbc.repositories] +* xref:reference:web/spring-hateoas.adoc#web.spring-hateoas[#features.spring-hateoas] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.message-codes[#features.developing-web-applications.spring-mvc.message-codes] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc[#features.developing-web-applications.spring-mvc] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.auto-configuration[#features.developing-web-applications.spring-mvc.auto-configuration] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.message-converters[#features.developing-web-applications.spring-mvc.message-converters] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.content-negotiation[#features.developing-web-applications.spring-mvc.content-negotiation] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.static-content[#features.developing-web-applications.spring-mvc.static-content] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.template-engines[#features.developing-web-applications.spring-mvc.template-engines] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.binding-initializer[#features.developing-web-applications.spring-mvc.binding-initializer] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.welcome-page[#features.developing-web-applications.spring-mvc.welcome-page] +* xref:reference:data/sql.adoc#data.sql[#features.sql] +* xref:reference:data/sql.adoc#data.sql.h2-web-console[#features.sql.h2-web-console] +* xref:reference:data/sql.adoc#data.sql.h2-web-console.custom-path[#features.sql.h2-web-console.custom-path] +* xref:reference:features/spring-application.adoc#features.spring-application.startup-failure[#boot-features-startup-failure] +* xref:reference:features/task-execution-and-scheduling.adoc#features.task-execution-and-scheduling[#boot-features-task-execution-scheduling] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.testing[#boot-features-test-autoconfig] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.testing.overriding-classpath[#boot-features-test-autoconfig-overriding-classpath] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.testing.simulating-a-web-context[#boot-features-test-autoconfig-simulating-web-context] +* xref:reference:testing/test-utilities.adoc#testing.utilities.test-property-values[#boot-features-test-property-values] +* xref:reference:testing/test-scope-dependencies.adoc#testing.test-scope-dependencies[#boot-features-test-scope-dependencies] +* xref:reference:testing/test-utilities.adoc#testing.utilities[#boot-features-test-utilities] +* xref:reference:testing/index.adoc#testing[#boot-features-testing] +* xref:reference:testing/spring-applications.adoc#testing.spring-applications[#boot-features-testing-spring-applications] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.using-application-arguments[#boot-features-testing-spring-boot-application-arguments] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications[#boot-features-testing-spring-boot-applications] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.customizing-web-test-client[#boot-features-testing-spring-boot-applications-customizing-web-test-client] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.detecting-configuration[#boot-features-testing-spring-boot-applications-detecting-config] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.detecting-web-app-type[#boot-features-testing-spring-boot-applications-detecting-web-app-type] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.excluding-configuration[#boot-features-testing-spring-boot-applications-excluding-config] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.jmx[#boot-features-testing-spring-boot-applications-jmx] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.metrics[#boot-features-testing-spring-boot-applications-metrics] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.mocking-beans[#boot-features-testing-spring-boot-applications-mocking-beans] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.additional-autoconfiguration-and-slicing[#boot-features-testing-spring-boot-applications-testing-auto-configured-additional-auto-config] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-cassandra[#boot-features-testing-spring-boot-applications-testing-autoconfigured-cassandra-test] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-jdbc[#boot-features-testing-spring-boot-applications-testing-autoconfigured-data-jdbc-test] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-jdbc[#boot-features-testing-spring-boot-applications-testing-autoconfigured-jdbc-test] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-jooq[#boot-features-testing-spring-boot-applications-testing-autoconfigured-jooq-test] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-jpa[#boot-features-testing-spring-boot-applications-testing-autoconfigured-jpa-test] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.json-tests[#boot-features-testing-spring-boot-applications-testing-autoconfigured-json-tests] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-ldap[#boot-features-testing-spring-boot-applications-testing-autoconfigured-ldap-test] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-mongodb[#boot-features-testing-spring-boot-applications-testing-autoconfigured-mongo-test] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.spring-mvc-tests[#boot-features-testing-spring-boot-applications-testing-autoconfigured-mvc-tests] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-neo4j[#boot-features-testing-spring-boot-applications-testing-autoconfigured-neo4j-test] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-redis[#boot-features-testing-spring-boot-applications-testing-autoconfigured-redis-test] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-rest-client[#boot-features-testing-spring-boot-applications-testing-autoconfigured-rest-client] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-restdocs[#boot-features-testing-spring-boot-applications-testing-autoconfigured-rest-docs] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-restdocs.with-mock-mvc[#boot-features-testing-spring-boot-applications-testing-autoconfigured-rest-docs-mock-mvc] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-restdocs.with-rest-assured[#boot-features-testing-spring-boot-applications-testing-autoconfigured-rest-docs-rest-assured] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-restdocs.with-web-test-client[#boot-features-testing-spring-boot-applications-testing-autoconfigured-rest-docs-web-test-client] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-tests[#boot-features-testing-spring-boot-applications-testing-autoconfigured-tests] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.spring-webflux-tests[#boot-features-testing-spring-boot-applications-testing-autoconfigured-webflux-tests] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-webservices[#boot-features-testing-spring-boot-applications-testing-autoconfigured-webservices] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.user-configuration-and-slicing[#boot-features-testing-spring-boot-applications-testing-user-configuration] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.with-mock-environment[#boot-features-testing-spring-boot-applications-testing-with-mock-environment] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.with-running-server[#boot-features-testing-spring-boot-applications-testing-with-running-server] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.spock[#boot-features-testing-spring-boot-applications-with-spock] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.understanding-auto-configured-beans[#boot-features-understanding-auto-configured-beans] +* xref:reference:messaging/amqp.adoc#messaging.amqp.receiving[#features.messaging.amqp.receiving] +* xref:reference:messaging/amqp.adoc#messaging.amqp.sending[#features.messaging.amqp.sending] +* xref:reference:data/sql.adoc#data.sql.jdbc-template[#features.sql.jdbc-template] +* xref:reference:messaging/jms.adoc#messaging.jms.receiving[#features.messaging.jms.receiving] +* xref:reference:messaging/jms.adoc#messaging.jms.sending[#features.messaging.jms.sending] +* xref:reference:io/validation.adoc#io.validation[#features.validation] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.web-application-conditions[#boot-features-web-application-conditions] +* xref:reference:features/spring-application.adoc#features.spring-application.web-environment[#boot-features-web-environment] +* xref:reference:io/rest-client.adoc#io.rest-client.webclient[#features.webclient] +* xref:reference:io/rest-client.adoc#io.rest-client.webclient.customization[#features.webclient.customization] +* xref:reference:io/rest-client.adoc#io.rest-client.webclient.runtime[#features.webclient.runtime] +* xref:reference:web/reactive.adoc#web.reactive.webflux[#features.developing-web-applications.spring-webflux] +* xref:reference:web/reactive.adoc#web.reactive.webflux.auto-configuration[#features.developing-web-applications.spring-webflux.auto-configuration] +* xref:reference:web/reactive.adoc#web.reactive.webflux.error-handling[#features.developing-web-applications.spring-webflux.error-handling] +* xref:reference:web/reactive.adoc#web.reactive.webflux.error-handling.error-pages[#features.developing-web-applications.spring-webflux.error-pages] +* xref:reference:web/reactive.adoc#web.reactive.webflux.httpcodecs[#features.developing-web-applications.spring-webflux.httpcodecs] +* xref:reference:web/reactive.adoc#web.reactive.webflux.static-content[#features.developing-web-applications.spring-webflux.static-context] +* xref:reference:web/reactive.adoc#web.reactive.webflux.template-engines[#features.developing-web-applications.spring-webflux.template-engines] +* xref:reference:web/reactive.adoc#web.reactive.webflux.web-filters[#features.developing-web-applications.spring-webflux.web-filters] +* xref:reference:web/reactive.adoc#web.reactive.webflux.welcome-page[#features.developing-web-applications.spring-webflux.welcome-page] +* xref:reference:io/webservices.adoc#io.webservices[#features.webservices] +* xref:reference:io/webservices.adoc#io.webservices.template[#features.webservices.template] +* xref:reference:messaging/websockets.adoc#messaging.websockets[#features.websockets] +* xref:reference:packaging/container-images/efficient-images.adoc#packaging.container-images.efficient-images.layering[#features.container-images.layering] +* xref:build-tool-plugin:index.adoc#build-tool-plugins[#build-tool-plugins] +* xref:build-tool-plugin:antlib.adoc#build-tool-plugins.antlib[#build-tool-plugins-antlib] +* xref:build-tool-plugin:other-build-systems.adoc#build-tool-plugins.other-build-systems.finding-main-class[#build-tool-plugins-find-a-main-class] +* xref:reference:using/build-systems.adoc#using.build-systems.gradle[#using-boot-gradle] +* xref:reference:using/build-systems.adoc#using.build-systems.maven[#using-boot-maven] +* xref:build-tool-plugin:other-build-systems.adoc#build-tool-plugins.other-build-systems.nested-libraries[#build-tool-plugins-nested-libraries] +* xref:build-tool-plugin:other-build-systems.adoc#build-tool-plugins.other-build-systems[#build-tool-plugins-other-build-systems] +* xref:build-tool-plugin:other-build-systems.adoc#build-tool-plugins.other-build-systems.example-repackage-implementation[#build-tool-plugins-repackage-implementation] +* xref:build-tool-plugin:other-build-systems.adoc#build-tool-plugins.other-build-systems.repackaging-archives[#build-tool-plugins-repackaging-archives] +* xref:cli:index.adoc#cli[#cli] +* xref:cli:using-the-cli.adoc#cli.using-the-cli.initialize-new-project[#cli-init] +* xref:cli:installation.adoc#cli.installation[#cli-installation] +* xref:cli:using-the-cli.adoc#cli.using-the-cli.embedded-shell[#cli-shell] +* xref:cli:using-the-cli.adoc#cli.using-the-cli[#cli-using-the-cli] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud[#cloud-deployment] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws[#cloud-deployment-aws] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws.beanstalk[#cloud-deployment-aws-beanstalk] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws.beanstalk.java-se-platform[#cloud-deployment-aws-java-se-platform] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws.summary[#cloud-deployment-aws-summary] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws.beanstalk.tomcat-platform[#cloud-deployment-aws-tomcat-platform] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.boxfuse[#cloud-deployment-boxfuse] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.cloud-foundry[#cloud-deployment-cloud-foundry] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.cloud-foundry.binding-to-services[#cloud-deployment-cloud-foundry-services] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.google[#cloud-deployment-gae] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.heroku[#cloud-deployment-heroku] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.kubernetes[#cloud-deployment-kubernetes] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.kubernetes.container-lifecycle[#cloud-deployment-kubernetes-container-lifecycle] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.openshift[#cloud-deployment-openshift] +* xref:specification:configuration-metadata/index.adoc#appendix.configuration-metadata[#configuration-metadata] +* xref:specification:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.adding-additional-metadata[#configuration-metadata.annotation-processor.adding-additional-metadata] +* xref:specification:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor[#configuration-metadata.annotation-processor] +* xref:specification:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.automatic-metadata-generation[#configuration-metadata.annotation-processor.automatic-metadata-generation] +* xref:specification:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.automatic-metadata-generation.nested-properties[#configuration-metadata.annotation-processor.automatic-metadata-generation.nested-properties] +* xref:specification:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.configuring[#configuration-metadata.annotation-processor.configuring] +* xref:specification:configuration-metadata/format.adoc#appendix.configuration-metadata.format[#configuration-metadata.format] +* xref:specification:configuration-metadata/format.adoc#appendix.configuration-metadata.format.group[#configuration-metadata.format.group] +* xref:specification:configuration-metadata/format.adoc#appendix.configuration-metadata.format.hints[#configuration-metadata.format.hints] +* xref:specification:configuration-metadata/format.adoc#appendix.configuration-metadata.format.property[#configuration-metadata.format.property] +* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints[#configuration-metadata.manual-hints] +* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers.any[#configuration-metadata.manual-hints.value-providers.any] +* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers.class-reference[#configuration-metadata.manual-hints.value-providers.class-reference] +* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers.handle-as[#configuration-metadata.manual-hints.value-providers.handle-as] +* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers.logger-name[#configuration-metadata.manual-hints.value-providers.logger-name] +* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers.spring-bean-reference[#configuration-metadata.manual-hints.value-providers.spring-bean-reference] +* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers.spring-profile-name[#configuration-metadata.manual-hints.value-providers.spring-profile-name] +* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-hint[#configuration-metadata.manual-hints.value-hint] +* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers[#configuration-metadata.manual-hints.value-providers] +* xref:specification:configuration-metadata/format.adoc#appendix.configuration-metadata.format.repeated-items[#configuration-metadata.format.repeated-items] +* xref:reference:using/devtools.adoc#using.devtools.globalsettings.configuring-file-system-watcher[#configuring-file-system-watcher] +* xref:reference:packaging/efficient.adoc#packaging.efficient.unpacking[#container-images.efficient-images.unpacking] +* xref:reference:data/nosql.adoc#data.nosql.elasticsearch.connecting-using-rest.reactiveclient[#data.nosql.elasticsearch.connecting-using-rest.webclient] +* xref:appendix:dependency-versions/index.adoc#appendix.dependency-versions[#dependency-versions] +* xref:appendix:dependency-versions/coordinates.adoc#appendix.dependency-versions.coordinates[#dependency-versions.coordinates] +* xref:appendix:dependency-versions/properties.adoc#appendix.dependency-versions.properties[#dependency-versions.properties] +* xref:how-to:deployment/index.adoc#howto.deployment[#deployment] +* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d[#deployment.installing.nix-services.init-d] +* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d.securing[#deployment.installing.nix-services.init-d.securing] +* xref:how-to:deployment/installing.adoc#howto.deployment.installing[#deployment.installing.supported-operating-systems] +* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d.script-customization[#deployment.installing.nix-services.script-customization] +* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d.script-customization.when-running[#deployment.installing.nix-services.script-customization.when-running] +* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d.script-customization.when-written[#deployment.installing.nix-services.script-customization.when-written] +* xref:how-to:deployment/installing.adoc#howto.deployment.installing.system-d[#deployment.installing.nix-services.system-d] +* xref:how-to:deployment/installing.adoc#howto.deployment.installing.windows-services[#deployment-windows] +* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d.script-customization.when-running.conf-file[#deployment.installing.nix-services.script-customization.when-running.conf-file] +* xref:specification:executable-jar/index.adoc#appendix.executable-jar[#executable-jar] +* xref:specification:executable-jar/alternatives.adoc#appendix.executable-jar.alternatives[#executable-jar.alternatives] +* xref:specification:executable-jar/nested-jars.adoc#appendix.executable-jar.nested-jars.jar-structure[#executable-jar.nested-jars.jar-structure] +* xref:specification:executable-jar/jarfile-class.adoc#appendix.executable-jar.jarfile-class[#executable-jar.jarfile-class] +* xref:specification:executable-jar/jarfile-class.adoc#appendix.executable-jar.jarfile-class.compatibility[#executable-jar.jarfile-class.compatibility] +* xref:specification:executable-jar/launching.adoc#appendix.executable-jar.launching.manifest[#executable-jar.launching.manifest] +* xref:specification:executable-jar/launching.adoc#appendix.executable-jar.launching[#executable-jar.launching] +* xref:specification:executable-jar/nested-jars.adoc#appendix.executable-jar.nested-jars[#executable-jar.nested-jars] +* xref:specification:executable-jar/property-launcher.adoc#appendix.executable-jar.property-launcher[#executable-jar.property-launcher] +* xref:specification:executable-jar/restrictions.adoc#appendix.executable-jar.restrictions[#executable-jar.restrictions] +* xref:specification:executable-jar/nested-jars.adoc#appendix.executable-jar.nested-jars.war-structure[#executable-jar.nested-jars.war-structure] +* xref:specification:executable-jar/nested-jars.adoc#appendix.executable-jar.nested-jars.index-files[#executable-jar.nested-jars.index-files] +* xref:specification:executable-jar/nested-jars.adoc#appendix.executable-jar.nested-jars.classpath-index[#executable-jar.nested-jars.classpath-index] +* xref:specification:executable-jar/nested-jars.adoc#appendix.executable-jar.nested-jars.layer-index[#executable-jar.nested-jars.layer-index] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.favicon[#features.developing-web-applications.spring-mvc.favicon] +* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.envers-repositories[#features.sql.jpa-and-spring-data.envers-repositories] +* xref:reference:features/dev-services.adoc#features.dev-services.testcontainers.at-development-time[#features.testing.testcontainers.at-development-time] +* xref:reference:features/dev-services.adoc#features.dev-services.testcontainers.at-development-time.devtools[#features.testing.testcontainers.at-development-time.devtools] +* xref:reference:features/dev-services.adoc#features.dev-services.testcontainers.at-development-time.dynamic-properties[#features.testing.testcontainers.at-development-time.dynamic-properties] +* xref:reference:features/dev-services.adoc#features.dev-services.testcontainers.at-development-time.importing-container-declarations[#features.testing.testcontainers.at-development-time.importing-container-declarations] +* xref:index.adoc[#index] +* xref:ROOT:installing.adoc#getting-started.installing.cli.completion[#getting-started-cli-command-line-completion] +* xref:tutorial:first-application/index.adoc#getting-started.first-application[#getting-started-first-application] +* xref:tutorial:first-application/index.adoc#getting-started.first-application.code.mvc-annotations[#getting-started-first-application-annotations] +* xref:tutorial:first-application/index.adoc#getting-started.first-application.code.spring-boot-application[#getting-started.first-application.code.enable-auto-configuration] +* xref:tutorial:first-application/index.adoc#getting-started.first-application.code[#getting-started-first-application-code] +* xref:tutorial:first-application/index.adoc#getting-started.first-application.dependencies[#getting-started-first-application-dependencies] +* xref:tutorial:first-application/index.adoc#getting-started.first-application.executable-jar[#getting-started-first-application-executable-jar] +* xref:tutorial:first-application/index.adoc#getting-started.first-application.code.main-method[#getting-started-first-application-main-method] +* xref:tutorial:first-application/index.adoc#getting-started.first-application.pom[#getting-started-first-application-pom] +* xref:tutorial:first-application/index.adoc#getting-started.first-application.run[#getting-started-first-application-run] +* xref:ROOT:installing.adoc#getting-started.installing.java.gradle[#getting-started-gradle-installation] +* xref:ROOT:installing.adoc#getting-started.installing.cli.homebrew[#getting-started-homebrew-cli-installation] +* xref:ROOT:installing.adoc#getting-started.installing.java[#getting-started-installation-instructions-for-java] +* xref:ROOT:installing.adoc#getting-started.installing[#getting-started-installing-spring-boot] +* xref:ROOT:installing.adoc#getting-started.installing.cli[#getting-started-installing-the-cli] +* xref:ROOT:installing.adoc#getting-started.installing.cli.macports[#getting-started-macports-cli-installation] +* xref:ROOT:installing.adoc#getting-started.installing.cli.manual-installation[#getting-started-manual-cli-installation] +* xref:ROOT:installing.adoc#getting-started.installing.java.maven[#getting-started-maven-installation] +* xref:ROOT:installing.adoc#getting-started.installing.cli.scoop[#getting-started-scoop-cli-installation] +* xref:ROOT:installing.adoc#getting-started.installing.cli.sdkman[#getting-started-sdkman-cli-installation] +* xref:ROOT:system-requirements.adoc#getting-started.system-requirements[#getting-started-system-requirements] +* xref:ROOT:system-requirements.adoc#getting-started.system-requirements.servlet-containers[#getting-started-system-requirements-servlet-containers] +* xref:ROOT:upgrading.adoc#upgrading[#getting-started.installing.upgrading] +* xref:how-to:webserver.adoc#howto.webserver.enable-response-compression[#how-to-enable-http-response-compression] +* xref:how-to:index.adoc#howto[#howto] +* xref:how-to:actuator.adoc#howto.actuator[#howto-actuator] +* xref:how-to:webserver.adoc#howto.webserver.add-servlet-filter-listener[#howto-add-a-servlet-filter-or-listener] +* xref:how-to:webserver.adoc#howto.webserver.add-servlet-filter-listener.spring-bean[#howto-add-a-servlet-filter-or-listener-as-spring-bean] +* xref:how-to:webserver.adoc#howto.webserver.add-servlet-filter-listener.using-scanning[#howto-add-a-servlet-filter-or-listener-using-scanning] +* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.expand-properties[#howto-automatic-expansion] +* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.expand-properties.gradle[#howto-automatic-expansion-gradle] +* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.expand-properties.maven[#howto-automatic-expansion-maven] +* xref:how-to:batch.adoc#howto.batch[#howto-batch-applications] +* xref:how-to:build.adoc#howto.build[#howto-build] +* xref:how-to:application.adoc#howto.application.context-hierarchy[#howto-build-an-application-context-hierarchy] +* xref:how-to:build.adoc#howto.build.build-an-executable-archive-with-ant-without-using-spring-boot-antlib[#howto-build-an-executable-archive-with-ant] +* xref:how-to:build.adoc#howto.build.generate-info[#howto-build-info] +* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.change-configuration-depending-on-the-environment[#howto-change-configuration-depending-on-the-environment] +* xref:how-to:webserver.adoc#howto.webserver.change-port[#howto-change-the-http-port] +* xref:how-to:actuator.adoc#howto.actuator.change-http-port-or-address[#howto-change-the-http-port-or-address-of-the-actuator-endpoints] +* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.external-properties-location[#howto-change-the-location-of-external-properties] +* xref:how-to:security.adoc#howto.security.change-user-details-service-and-add-user-accounts[#howto-change-the-user-details-service-and-add-user-accounts] +* xref:how-to:data-access.adoc#howto.data-access.configure-a-component-that-is-used-by-jpa[#howto-configure-a-component-that-is-used-by-JPA] +* xref:how-to:data-access.adoc#howto.data-access.configure-custom-datasource[#howto-configure-a-datasource] +* xref:how-to:webserver.adoc#howto.webserver.configure-access-logs[#howto-configure-accesslogs] +* xref:how-to:data-access.adoc#howto.data-access.configure-hibernate-naming-strategy[#howto-configure-hibernate-naming-strategy] +* xref:how-to:data-access.adoc#howto.data-access.configure-hibernate-second-level-caching[#howto-configure-hibernate-second-level-caching] +* xref:how-to:webserver.adoc#howto.webserver.configure-http2[#howto-configure-http2] +* xref:how-to:webserver.adoc#howto.webserver.configure-http2.jetty[#howto-configure-http2-jetty] +* xref:how-to:webserver.adoc#howto.webserver.configure-http2.netty[#howto-configure-http2-netty] +* xref:how-to:webserver.adoc#howto.webserver.configure-http2.tomcat[#howto-configure-http2-tomcat] +* xref:how-to:webserver.adoc#howto.webserver.configure-http2.undertow[#howto-configure-http2-undertow] +* xref:how-to:data-access.adoc#howto.data-access.configure-jooq-with-multiple-datasources[#howto-configure-jOOQ-with-multiple-datasources] +* xref:how-to:data-access.adoc#howto.data-access.jpa-properties[#howto-configure-jpa-properties] +* xref:how-to:logging.adoc#howto.logging.log4j[#howto-configure-log4j-for-logging] +* xref:how-to:logging.adoc#howto.logging.log4j.yaml-or-json-config[#howto-configure-log4j-for-logging-yaml-or-json-config] +* xref:how-to:logging.adoc#howto.logging.logback[#howto-configure-logback-for-logging] +* xref:how-to:logging.adoc#howto.logging.logback.file-only-output[#howto-configure-logback-for-logging-fileonly] +* xref:how-to:webserver.adoc#howto.webserver.configure-ssl[#howto-configure-ssl] +* xref:how-to:webserver.adoc#howto.webserver.configure[#howto-configure-webserver] +* xref:how-to:deployment/traditional-deployment.adoc#howto.traditional-deployment.convert-existing-application[#howto-convert-an-existing-application-to-spring-boot] +* xref:how-to:deployment/traditional-deployment.adoc#howto.traditional-deployment.war[#howto-create-a-deployable-war-file] +* xref:how-to:application.adoc#howto.application.non-web-application[#howto-create-a-non-web-application] +* xref:how-to:build.adoc#howto.build.create-a-nonexecutable-jar[#howto-create-a-nonexecutable-jar] +* xref:how-to:build.adoc#howto.build.use-a-spring-boot-application-as-dependency[#howto-create-an-additional-executable-jar] +* xref:how-to:build.adoc#howto.build.create-an-executable-jar-with-maven[#howto-create-an-executable-jar-with-maven] +* xref:how-to:webserver.adoc#howto.webserver.create-websocket-endpoints-using-serverendpoint[#howto-create-websocket-endpoints-using-serverendpoint] +* xref:how-to:build.adoc#howto.build.customize-dependency-versions[#howto-customize-dependency-versions] +* xref:how-to:application.adoc#howto.application.customize-the-environment-or-application-context[#howto-customize-the-environment-or-application-context] +* xref:how-to:spring-mvc.adoc#howto.spring-mvc.customize-jackson-objectmapper[#howto-customize-the-jackson-objectmapper] +* xref:how-to:spring-mvc.adoc#howto.spring-mvc.customize-responsebody-rendering[#howto-customize-the-responsebody-rendering] +* xref:how-to:spring-mvc.adoc#howto.spring-mvc.customize-whitelabel-error-page[#howto-customize-the-whitelabel-error-page] +* xref:how-to:webserver.adoc#howto.webserver.use-behind-a-proxy-server.tomcat[#howto-customize-tomcat-behind-a-proxy-server] +* xref:how-to:spring-mvc.adoc#howto.spring-mvc.customize-view-resolvers[#howto-customize-view-resolvers] +* xref:how-to:data-access.adoc#howto.data-access[#howto-data-access] +* xref:how-to:data-initialization.adoc#howto.data-initialization[#howto-database-initialization] +* xref:how-to:webserver.adoc#howto.webserver.add-servlet-filter-listener.spring-bean.disable[#howto-disable-registration-of-a-servlet-or-filter] +* xref:how-to:webserver.adoc#howto.webserver.disable[#howto-disable-web-server] +* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.discover-build-in-options-for-external-properties[#howto-discover-build-in-options-for-external-properties] +* xref:how-to:webserver.adoc#howto.webserver.discover-port[#howto-discover-the-http-port-at-runtime] +* xref:how-to:webserver.adoc#howto.webserver[#howto-embedded-web-servers] +* xref:how-to:security.adoc#howto.security.enable-https[#howto-enable-https] +* xref:how-to:webserver.adoc#howto.webserver.enable-multiple-connectors-in-tomcat[#howto-enable-multiple-connectors-in-tomcat] +* xref:how-to:webserver.adoc#howto.webserver.enable-multiple-listeners-in-undertow[#howto-enable-multiple-listeners-in-undertow] +* xref:how-to:webserver.adoc#howto.webserver.enable-tomcat-mbean-registry[#howto-enable-tomcat-mbean-registry] +* xref:how-to:data-initialization.adoc#howto.data-initialization.migration-tool.flyway[#howto-execute-flyway-database-migrations-on-startup] +* xref:how-to:data-initialization.adoc#howto.data-initialization.migration-tool.liquibase[#howto-execute-liquibase-database-migrations-on-startup] +* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.externalize-configuration[#howto-externalize-configuration] +* xref:how-to:build.adoc#howto.build.extract-specific-libraries-when-an-executable-jar-runs[#howto-extract-specific-libraries-when-an-executable-jar-runs] +* xref:how-to:application.adoc#howto.application.failure-analyzer[#howto-failure-analyzer] +* xref:how-to:build.adoc#howto.build.generate-git-info[#howto-git-info] +* xref:how-to:hotswapping.adoc#howto.hotswapping[#howto-hotswapping] +* xref:how-to:http-clients.adoc#howto.http-clients[#howto-http-clients] +* xref:how-to:http-clients.adoc#howto.http-clients.rest-template-proxy-configuration[#howto-http-clients-proxy-configuration] +* xref:how-to:data-initialization.adoc#howto.data-initialization.dependencies[#howto-initialize-a-database-configuring-dependencies] +* xref:how-to:data-initialization.adoc#howto.data-initialization.dependencies.depends-on-initialization-detection[#howto-initialize-a-database-configuring-dependencies-depends-on-initialization-detection] +* xref:how-to:data-initialization.adoc#howto.data-initialization.dependencies.initializer-detection[#howto-initialize-a-database-configuring-dependencies-initializer-detection] +* xref:how-to:data-initialization.adoc#howto.data-initialization.using-basic-sql-scripts[#howto-initialize-a-database-using-basic-scripts] +* xref:how-to:data-initialization.adoc#howto.data-initialization.using-hibernate[#howto.data-initialization.using-jpa] +* xref:how-to:data-initialization.adoc#howto.data-initialization.batch[#howto-initialize-a-spring-batch-database] +* xref:how-to:jersey.adoc#howto.jersey[#howto-jersey] +* xref:how-to:jersey.adoc#howto.jersey.alongside-another-web-framework[#howto-jersey-alongside-another-web-framework] +* xref:how-to:jersey.adoc#howto.jersey.spring-security[#howto-jersey-spring-security] +* xref:how-to:messaging.adoc#howto.messaging.disable-transacted-jms-session[#howto-jms-disable-transaction] +* xref:how-to:logging.adoc#howto.logging[#howto-logging] +* xref:how-to:actuator.adoc#howto.actuator.map-health-indicators-to-metrics[#howto-map-health-indicators-to-metrics] +* xref:how-to:messaging.adoc#howto.messaging[#howto-messaging] +* xref:how-to:spring-mvc.adoc#howto.spring-mvc.multipart-file-uploads[#howto-multipart-file-upload-configuration] +* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration[#howto-properties-and-configuration] +* xref:how-to:hotswapping.adoc#howto.hotswapping.fast-application-restarts[#howto-reload-fast-restart] +* xref:how-to:hotswapping.adoc#howto.hotswapping.reload-templates.freemarker[#howto-reload-freemarker-content] +* xref:how-to:hotswapping.adoc#howto.hotswapping.reload-templates.groovy[#howto-reload-groovy-template-content] +* xref:how-to:hotswapping.adoc#howto.hotswapping.reload-java-classes-without-restarting[#howto-reload-java-classes-without-restarting] +* xref:how-to:hotswapping.adoc#howto.hotswapping.reload-static-content[#howto-reload-static-content] +* xref:how-to:hotswapping.adoc#howto.hotswapping.reload-templates.thymeleaf[#howto-reload-thymeleaf-content] +* xref:how-to:hotswapping.adoc#howto.hotswapping.reload-templates[#howto-reload-thymeleaf-template-content] +* xref:how-to:build.adoc#howto.build.remote-debug-maven[#howto-remote-debug-maven-run] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.sanitization[#howto.actuator.sanitize-sensitive-values] +* xref:how-to:security.adoc#howto.security[#howto-security] +* xref:how-to:data-access.adoc#howto.data-access.separate-entity-definitions-from-spring-configuration[#howto-separate-entity-definitions-from-spring-configuration] +* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.set-active-spring-profiles[#howto-set-active-spring-profiles] +* xref:how-to:batch.adoc#howto.batch.running-from-the-command-line[#howto-spring-batch-running-command-line] +* xref:how-to:batch.adoc#howto.batch.running-jobs-on-startup[#howto-spring-batch-running-jobs-on-startup] +* xref:how-to:batch.adoc#howto.batch.specifying-a-data-source[#howto-spring-batch-specifying-a-data-source] +* xref:how-to:batch.adoc#howto.batch.storing-job-repository[#howto-spring-batch-storing-job-repository] +* xref:how-to:application.adoc#howto.application[#howto-spring-boot-application] +* xref:how-to:spring-mvc.adoc#howto.spring-mvc[#howto-spring-mvc] +* xref:how-to:spring-mvc.adoc#howto.spring-mvc.switch-off-default-configuration[#howto-switch-off-default-mvc-configuration] +* xref:how-to:security.adoc#howto.security.switch-off-spring-boot-configuration[#howto-switch-off-spring-boot-security-configuration] +* xref:how-to:spring-mvc.adoc#howto.spring-mvc.switch-off-dispatcherservlet[#howto-switch-off-the-spring-mvc-dispatcherservlet] +* xref:reference:testing/testcontainers.adoc#testing.testcontainers[#howto.testing.testcontainers] +* xref:how-to:deployment/traditional-deployment.adoc#howto.traditional-deployment[#howto-traditional-deployment] +* xref:how-to:application.adoc#howto.application.troubleshoot-auto-configuration[#howto-troubleshoot-auto-configuration] +* xref:how-to:data-access.adoc#howto.data-access.configure-two-datasources[#howto-two-datasources] +* xref:how-to:data-initialization.adoc#howto.data-initialization.migration-tool[#howto-use-a-higher-level-database-migration-tool] +* xref:how-to:webserver.adoc#howto.webserver.use-another[#howto-use-another-web-server] +* xref:how-to:webserver.adoc#howto.webserver.use-behind-a-proxy-server[#howto-use-behind-a-proxy-server] +* xref:how-to:data-access.adoc#howto.data-access.use-custom-entity-manager[#howto-use-custom-entity-manager] +* xref:how-to:data-access.adoc#howto.data-access.customize-spring-data-web-support[#howto-use-customize-spring-datas-web-support] +* xref:how-to:data-access.adoc#howto.data-access.dependency-injection-in-hibernate-components[#howto-use-dependency-injection-hibernate-components] +* xref:how-to:data-access.adoc#howto.data-access.exposing-spring-data-repositories-as-rest[#howto-use-exposing-spring-data-repositories-rest-endpoint] +* xref:how-to:nosql.adoc#howto.nosql.jedis-instead-of-lettuce[#howto-use-jedis-instead-of-lettuce] +* xref:how-to:data-access.adoc#howto.data-access.use-multiple-entity-managers[#howto-use-two-entity-managers] +* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.short-command-line-arguments[#howto-use-short-command-line-arguments] +* xref:how-to:data-access.adoc#howto.data-access.use-spring-data-jpa-and-mongo-repositories[#howto-use-spring-data-jpa--and-mongo-repositories] +* xref:how-to:data-access.adoc#howto.data-access.spring-data-repositories[#howto-use-spring-data-repositories] +* xref:how-to:testing.adoc#howto.testing.with-spring-security[#howto.spring-mvc.testing.with-spring-security] +* xref:how-to:data-access.adoc#howto.data-access.use-traditional-persistence-xml[#howto-use-traditional-persistence-xml] +* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.yaml[#howto-use-yaml-for-external-properties] +* xref:how-to:webserver.adoc#howto.webserver.use-random-port[#howto-user-a-random-unassigned-http-port] +* xref:how-to:http-clients.adoc#howto.http-clients.webclient-reactor-netty-customization[#howto-webclient-reactor-netty-customization] +* xref:how-to:deployment/traditional-deployment.adoc#howto.traditional-deployment.weblogic[#howto-weblogic] +* xref:how-to:spring-mvc.adoc#howto.spring-mvc.write-json-rest-service[#howto-write-a-json-rest-service] +* xref:how-to:spring-mvc.adoc#howto.spring-mvc.write-xml-rest-service[#howto-write-an-xml-rest-service] +* xref:how-to:actuator.adoc#howto.actuator.customizing-sanitization[#howto.actuator.sanitize-sensitive-values.customizing-sanitization] +* xref:reference:testing/testcontainers.adoc#testing.testcontainers.dynamic-properties[#howto.testing.testcontainers.dynamic-properties] +* xref:reference:actuator/index.adoc#actuator[#production-ready] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.info[#production-ready-application-info] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.info.auto-configured-info-contributors[#production-ready-application-info-autoconfigure] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.info.build-information[#production-ready-application-info-build] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.info.writing-custom-info-contributors[#production-ready-application-info-custom] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.info.custom-application-information[#production-ready-application-info-env] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.info.git-commit-information[#production-ready-application-info-git] +* xref:reference:actuator/auditing.adoc#actuator.auditing[#production-ready-auditing] +* xref:reference:actuator/auditing.adoc#actuator.auditing.custom[#production-ready-auditing-custom] +* xref:reference:actuator/cloud-foundry.adoc#actuator.cloud-foundry[#production-ready-cloudfoundry] +* xref:reference:actuator/cloud-foundry.adoc#actuator.cloud-foundry.disable[#production-ready-cloudfoundry-disable] +* xref:reference:actuator/cloud-foundry.adoc#actuator.cloud-foundry.ssl[#production-ready-cloudfoundry-ssl] +* xref:reference:actuator/cloud-foundry.adoc#actuator.cloud-foundry.custom-context-path[#production-ready-custom-context-path] +* xref:reference:actuator/jmx.adoc#actuator.jmx.custom-mbean-names[#production-ready-custom-mbean-names] +* xref:reference:actuator/monitoring.adoc#actuator.monitoring.customizing-management-server-address[#production-ready-customizing-management-server-address] +* xref:reference:actuator/monitoring.adoc#actuator.monitoring.customizing-management-server-context-path[#production-ready-customizing-management-server-context-path] +* xref:reference:actuator/monitoring.adoc#actuator.monitoring.customizing-management-server-port[#production-ready-customizing-management-server-port] +* xref:reference:actuator/jmx.adoc#actuator.jmx.disable-jmx-endpoints[#production-ready-disable-jmx-endpoints] +* xref:reference:actuator/monitoring.adoc#actuator.monitoring.disabling-http-endpoints[#production-ready-disabling-http-endpoints] +* xref:reference:actuator/enabling.adoc#actuator.enabling[#production-ready-enabling] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints[#production-ready-endpoints] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.caching[#production-ready-endpoints-caching] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.cors[#production-ready-endpoints-cors] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom[#production-ready-endpoints-custom] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.input[#production-ready-endpoints-custom-input] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.input.conversion[#production-ready-endpoints-custom-input-conversion] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web[#production-ready-endpoints-custom-web] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.request-predicates[#production-ready-endpoints-custom-web-predicate] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.consumes-predicates[#production-ready-endpoints-custom-web-predicate-consumes] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.method-predicates[#production-ready-endpoints-custom-web-predicate-http-method] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.path-predicates[#production-ready-endpoints-custom-web-predicate-path] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.produces-predicates[#production-ready-endpoints-custom-web-predicate-produces] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.range-requests[#production-ready-endpoints-custom-web-range-requests] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.response-status[#production-ready-endpoints-custom-web-response-status] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.security[#production-ready-endpoints-custom-web-security] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.enabling[#production-ready-endpoints-enabling-endpoints] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.exposing[#production-ready-endpoints-exposing-endpoints] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.hypermedia[#production-ready-endpoints-hypermedia] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.health[#production-ready-health] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.health.datasource[#production-ready-health-datasource] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.health.groups[#production-ready-health-groups] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.health.auto-configured-health-indicators[#production-ready-health-indicators] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.health.writing-custom-health-indicators[#production-ready-health-indicators-writing] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.kubernetes-probes[#production-ready-kubernetes-probes] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.kubernetes-probes.external-state[#production-ready-kubernetes-probes-external-state] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.kubernetes-probes.lifecycle[#production-ready-kubernetes-probes-lifecycle] +* xref:reference:actuator/loggers.adoc#actuator.loggers.configure[#production-ready-logger-configuration] +* xref:reference:actuator/loggers.adoc#actuator.loggers[#production-ready-loggers] +* xref:reference:actuator/monitoring.adoc#actuator.monitoring.management-specific-ssl[#production-ready-management-specific-ssl] +* xref:reference:actuator/metrics.adoc#actuator.metrics[#production-ready-metrics] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.cache[#production-ready-metrics-cache] +* xref:reference:actuator/metrics.adoc#actuator.metrics.customizing.common-tags[#production-ready-metrics-common-tags] +* xref:reference:actuator/metrics.adoc#actuator.metrics.registering-custom[#production-ready-metrics-custom] +* xref:reference:actuator/metrics.adoc#actuator.metrics.customizing[#production-ready-metrics-customizing] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.spring-data-repository[#production-ready-metrics-data-repository] +* xref:reference:actuator/metrics.adoc#actuator.metrics.endpoint[#production-ready-metrics-endpoint] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export[#production-ready-metrics-export] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export.appoptics[#production-ready-metrics-export-appoptics] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export.atlas[#production-ready-metrics-export-atlas] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export.datadog[#production-ready-metrics-export-datadog] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export.dynatrace[#production-ready-metrics-export-dynatrace] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export.elastic[#production-ready-metrics-export-elastic] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export.ganglia[#production-ready-metrics-export-ganglia] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export.graphite[#production-ready-metrics-export-graphite] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export.humio[#production-ready-metrics-export-humio] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export.influx[#production-ready-metrics-export-influx] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export.jmx[#production-ready-metrics-export-jmx] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export.kairos[#production-ready-metrics-export-kairos] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export.newrelic[#production-ready-metrics-export-newrelic] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export.prometheus[#production-ready-metrics-export-prometheus] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export.signalfx[#production-ready-metrics-export-signalfx] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export.simple[#production-ready-metrics-export-simple] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export.stackdriver[#production-ready-metrics-export-stackdriver] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export.statsd[#production-ready-metrics-export-statsd] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export.wavefront[#production-ready-metrics-export-wavefront] +* xref:reference:actuator/metrics.adoc#actuator.metrics.getting-started[#production-ready-metrics-getting-started] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.hibernate[#production-ready-metrics-hibernate] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.http-clients[#production-ready-metrics-http-clients] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.spring-integration[#production-ready-metrics-integration] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.jdbc[#production-ready-metrics-jdbc] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.jersey[#production-ready-metrics-jersey-server] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.jvm[#production-ready-metrics-jvm] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.kafka[#production-ready-metrics-kafka] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.logger[#production-ready-metrics-logger] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported[#production-ready-metrics-meter] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.mongodb[#production-ready-metrics-mongodb] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.mongodb.command[#production-ready-metrics-mongodb-command] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.mongodb.connection-pool[#production-ready-metrics-mongodb-connectionpool] +* xref:reference:actuator/metrics.adoc#actuator.metrics.customizing.per-meter-properties[#production-ready-metrics-per-meter-properties] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.rabbitmq[#production-ready-metrics-rabbitmq] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.spring-mvc[#production-ready-metrics-spring-mvc] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.system[#production-ready-metrics-system] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.timed-annotation[#production-ready-metrics-timed-annotation] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.tomcat[#production-ready-metrics-tomcat] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.spring-webflux[#production-ready-metrics-web-flux] +* xref:reference:actuator/monitoring.adoc#actuator.monitoring[#production-ready-monitoring] +* xref:reference:actuator/process-monitoring.adoc#actuator.process-monitoring[#production-ready-process-monitoring] +* xref:reference:actuator/process-monitoring.adoc#actuator.process-monitoring.configuration[#production-ready-process-monitoring-configuration] +* xref:reference:actuator/process-monitoring.adoc#actuator.process-monitoring.programmatically[#production-ready-process-monitoring-programmatically] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.health.reactive-health-indicators[#reactive-health-indicators] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.health.auto-configured-reactive-health-indicators[#reactive-health-indicators-autoconfigured] +* xref:reference:using/devtools.adoc#using.devtools.remote-applications.client[#running-remote-client-application] +* xref:build-tool-plugin:antlib.adoc#build-tool-plugins.antlib.tasks.exejar[#spring-boot-ant-exejar] +* xref:build-tool-plugin:antlib.adoc#build-tool-plugins.antlib.tasks.examples[#spring-boot-ant-exejar-examples] +* xref:build-tool-plugin:antlib.adoc#build-tool-plugins.antlib.findmainclass[#spring-boot-ant-findmainclass] +* xref:build-tool-plugin:antlib.adoc#build-tool-plugins.antlib.findmainclass.examples[#spring-boot-ant-findmainclass-examples] +* xref:build-tool-plugin:antlib.adoc#build-tool-plugins.antlib.tasks[#spring-boot-ant-tasks] +* xref:appendix:test-auto-configuration/index.adoc#appendix.test-auto-configuration[#test-auto-configuration] +* xref:appendix:test-auto-configuration/slices.adoc#appendix.test-auto-configuration.slices[#test-auto-configuration.slices] +* xref:reference:using/index.adoc#using[#using-boot] +* xref:reference:using/build-systems.adoc#using.build-systems.ant[#using-boot-ant] +* xref:reference:using/auto-configuration.adoc#using.auto-configuration[#using-boot-auto-configuration] +* xref:reference:using/build-systems.adoc#using.build-systems[#using-boot-build-systems] +* xref:reference:using/configuration-classes.adoc#using.configuration-classes[#using-boot-configuration-classes] +* xref:reference:using/build-systems.adoc#using.build-systems.dependency-management[#using-boot-dependency-management] +* xref:reference:using/devtools.adoc#using.devtools[#using-boot-devtools] +* xref:reference:using/devtools.adoc#using.devtools.restart.customizing-the-classload[#using-boot-devtools-customizing-classload] +* xref:reference:using/devtools.adoc#using.devtools.globalsettings[#using-boot-devtools-globalsettings] +* xref:reference:using/devtools.adoc#using.devtools.restart.limitations[#using-boot-devtools-known-restart-limitations] +* xref:reference:using/devtools.adoc#using.devtools.livereload[#using-boot-devtools-livereload] +* xref:reference:using/devtools.adoc#using.devtools.property-defaults[#using-boot-devtools-property-defaults] +* xref:reference:using/devtools.adoc#using.devtools.remote-applications[#using-boot-devtools-remote] +* xref:reference:using/devtools.adoc#using.devtools.remote-applications.update[#using-boot-devtools-remote-update] +* xref:reference:using/devtools.adoc#using.devtools.restart[#using-boot-devtools-restart] +* xref:reference:using/devtools.adoc#using.devtools.restart.watching-additional-paths[#using-boot-devtools-restart-additional-paths] +* xref:reference:using/devtools.adoc#using.devtools.restart.disable[#using-boot-devtools-restart-disable] +* xref:reference:using/devtools.adoc#using.devtools.restart.excluding-resources[#using-boot-devtools-restart-exclude] +* xref:reference:using/devtools.adoc#using.devtools.restart.logging-condition-delta[#using-boot-devtools-restart-logging-condition-delta] +* xref:reference:using/devtools.adoc#using.devtools.restart.triggerfile[#using-boot-devtools-restart-triggerfile] +* xref:reference:using/auto-configuration.adoc#using.auto-configuration.disabling-specific[#using-boot-disabling-specific-auto-configuration] +* xref:reference:using/running-your-application.adoc#using.running-your-application.hot-swapping[#using-boot-hot-swapping] +* xref:reference:using/configuration-classes.adoc#using.configuration-classes.importing-additional-configuration[#using-boot-importing-configuration] +* xref:reference:using/configuration-classes.adoc#using.configuration-classes.importing-xml-configuration[#using-boot-importing-xml-configuration] +* xref:reference:using/structuring-your-code.adoc#using.structuring-your-code.locating-the-main-class[#using-boot-locating-the-main-class] +* xref:reference:using/packaging-for-production.adoc#using.packaging-for-production[#using-boot-packaging-for-production] +* xref:reference:using/auto-configuration.adoc#using.auto-configuration.replacing[#using-boot-replacing-auto-configuration] +* xref:reference:using/running-your-application.adoc#using.running-your-application.as-a-packaged-application[#using-boot-running-as-a-packaged-application] +* xref:reference:using/running-your-application.adoc#using.running-your-application.from-an-ide[#using-boot-running-from-an-ide] +* xref:reference:using/running-your-application.adoc#using.running-your-application.with-the-gradle-plugin[#using-boot-running-with-the-gradle-plugin] +* xref:reference:using/running-your-application.adoc#using.running-your-application.with-the-maven-plugin[#using-boot-running-with-the-maven-plugin] +* xref:reference:using/running-your-application.adoc#using.running-your-application[#using-boot-running-your-application] +* xref:reference:using/spring-beans-and-dependency-injection.adoc#using.spring-beans-and-dependency-injection[#using-boot-spring-beans-and-dependency-injection] +* xref:reference:using/build-systems.adoc#using.build-systems.starters[#using-boot-starter] +* xref:reference:using/structuring-your-code.adoc#using.structuring-your-code[#using-boot-structuring-your-code] +* xref:reference:using/using-the-springbootapplication-annotation.adoc#using.using-the-springbootapplication-annotation[#using-boot-using-springbootapplication-annotation] +* xref:reference:using/structuring-your-code.adoc#using.structuring-your-code.using-the-default-package[#using-boot-using-the-default-package] +* xref:reference:using/devtools.adoc#using.devtools.restart.restart-vs-reload[#using-spring-boot-restart-vs-reload] From 3dcea98f000a9104c95b31dc1e694660d88976cb Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 3 Dec 2024 20:24:54 -0800 Subject: [PATCH 043/203] Polish `redirect.adoc` by sorting contents alphabetically --- .../antora/modules/ROOT/pages/redirect.adoc | 2676 ++++++++--------- 1 file changed, 1335 insertions(+), 1341 deletions(-) diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/ROOT/pages/redirect.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/ROOT/pages/redirect.adoc index 6ec633abbe4c..f13b183055c2 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/ROOT/pages/redirect.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/ROOT/pages/redirect.adoc @@ -1,486 +1,728 @@ :page-layout: redirect -* xref:community.adoc[getting-help] -* xref:documentation.adoc[documentation] -* xref:index.adoc[getting-started] -* xref:upgrading.adoc[upgrading] -* xref:reference:using/index.adoc#using[using] -* xref:reference:features/index.adoc[features] -* xref:reference:web/index.adoc[web] -* xref:reference:data/index.adoc[data] -* xref:reference:io/index.adoc[io] -* xref:reference:messaging/index.adoc[messaging] -* xref:reference:packaging/container-images/index.adoc[container-images] -* xref:reference:actuator/index.adoc[actuator] -* xref:how-to:deployment/index.adoc[deployment] -* xref:reference:packaging/native-image/index.adoc[native-image] -* xref:cli:index.adoc[cli] -* xref:build-tool-plugin:index.adoc[build-tool-plugins] -* xref:how-to:index.adoc[howto] -* xref:appendix:application-properties/index.adoc[application-properties] -* xref:specification:configuration-metadata/index.adoc[configuration-metadata] -* xref:appendix:auto-configuration-classes/index.adoc[auto-configuration-classes] -* xref:appendix:test-auto-configuration/index.adoc[test-auto-configuration] -* xref:specification:executable-jar/index.adoc[executable-jar] -* xref:appendix:dependency-versions/index.adoc[dependency-versions] -* xref:community.adoc[#getting-help] -* xref:community.adoc[#documentation.getting-help] -* xref:documentation.adoc[#documentation] -* xref:documentation.adoc[#documentation.about] -* xref:index.adoc[#getting-started] -* xref:upgrading.adoc[#upgrading] -* xref:reference:using/index.adoc#using[#using] -* xref:reference:features/index.adoc[#features] -* xref:reference:web/index.adoc[#web] -* xref:reference:data/index.adoc[#data] -* xref:reference:io/index.adoc[#io] -* xref:reference:messaging/index.adoc[#messaging] -* xref:reference:packaging/container-images/index.adoc[#container-images] -* xref:reference:actuator/index.adoc[#actuator] -* xref:how-to:deployment/index.adoc[#deployment] -* xref:reference:packaging/native-image/index.adoc[#native-image] -* xref:cli:index.adoc[#cli] -* xref:build-tool-plugin:index.adoc[#build-tool-plugins] -* xref:how-to:index.adoc[#howto] -* xref:appendix:application-properties/index.adoc[#application-properties] -* xref:specification:configuration-metadata/index.adoc[#configuration-metadata] -* xref:appendix:auto-configuration-classes/index.adoc[#auto-configuration-classes] -* xref:appendix:test-auto-configuration/index.adoc[#test-auto-configuration] -* xref:specification:executable-jar/index.adoc[#executable-jar] -* xref:appendix:dependency-versions/index.adoc[#dependency-versions] -* xref:ROOT:community.adoc#community[#community] * xref:ROOT:community.adoc#community[#boot-documentation-getting-help] -* xref:ROOT:documentation.adoc#documentation[#documentation] +* xref:ROOT:community.adoc#community[#community] +* xref:ROOT:documentation.adoc#documentation.actuator[#boot-documentation-production] * xref:ROOT:documentation.adoc#documentation.actuator[#documentation.actuator] +* xref:ROOT:documentation.adoc#documentation.advanced[#boot-documentation-advanced] * xref:ROOT:documentation.adoc#documentation.advanced[#documentation.advanced] * xref:ROOT:documentation.adoc#documentation.container-images[#documentation.container-images] * xref:ROOT:documentation.adoc#documentation.data[#documentation.data] +* xref:ROOT:documentation.adoc#documentation.features[#boot-documentation-learning] * xref:ROOT:documentation.adoc#documentation.features[#documentation.features] +* xref:ROOT:documentation.adoc#documentation.first-steps[#boot-documentation-first-steps] * xref:ROOT:documentation.adoc#documentation.first-steps[#documentation.first-steps] * xref:ROOT:documentation.adoc#documentation.io[#documentation.io] * xref:ROOT:documentation.adoc#documentation.messaging[#documentation.messaging] * xref:ROOT:documentation.adoc#documentation.packaging[#documentation.packaging] +* xref:ROOT:documentation.adoc#documentation.upgrading[#boot-documentation-upgrading] * xref:ROOT:documentation.adoc#documentation.upgrading[#documentation.upgrading] +* xref:ROOT:documentation.adoc#documentation.using[#boot-documentation-workingwith] * xref:ROOT:documentation.adoc#documentation.using[#documentation.using] * xref:ROOT:documentation.adoc#documentation.web[#documentation.web] -* xref:ROOT:installing.adoc#getting-started.installing[#getting-started.installing] -* xref:ROOT:installing.adoc#getting-started.installing.cli[#getting-started.installing.cli] +* xref:ROOT:documentation.adoc#documentation[#boot-documentation] +* xref:ROOT:documentation.adoc#documentation[#documentation] +* xref:ROOT:installing.adoc#getting-started.installing.cli.completion[#getting-started-cli-command-line-completion] * xref:ROOT:installing.adoc#getting-started.installing.cli.completion[#getting-started.installing.cli.completion] +* xref:ROOT:installing.adoc#getting-started.installing.cli.homebrew[#getting-started-homebrew-cli-installation] * xref:ROOT:installing.adoc#getting-started.installing.cli.homebrew[#getting-started.installing.cli.homebrew] +* xref:ROOT:installing.adoc#getting-started.installing.cli.macports[#getting-started-macports-cli-installation] * xref:ROOT:installing.adoc#getting-started.installing.cli.macports[#getting-started.installing.cli.macports] +* xref:ROOT:installing.adoc#getting-started.installing.cli.manual-installation[#getting-started-manual-cli-installation] * xref:ROOT:installing.adoc#getting-started.installing.cli.manual-installation[#getting-started.installing.cli.manual-installation] +* xref:ROOT:installing.adoc#getting-started.installing.cli.scoop[#getting-started-scoop-cli-installation] * xref:ROOT:installing.adoc#getting-started.installing.cli.scoop[#getting-started.installing.cli.scoop] +* xref:ROOT:installing.adoc#getting-started.installing.cli.sdkman[#getting-started-sdkman-cli-installation] * xref:ROOT:installing.adoc#getting-started.installing.cli.sdkman[#getting-started.installing.cli.sdkman] -* xref:ROOT:installing.adoc#getting-started.installing.java[#getting-started.installing.java] +* xref:ROOT:installing.adoc#getting-started.installing.cli[#getting-started-installing-the-cli] +* xref:ROOT:installing.adoc#getting-started.installing.cli[#getting-started.installing.cli] +* xref:ROOT:installing.adoc#getting-started.installing.java.gradle[#getting-started-gradle-installation] * xref:ROOT:installing.adoc#getting-started.installing.java.gradle[#getting-started.installing.java.gradle] +* xref:ROOT:installing.adoc#getting-started.installing.java.maven[#getting-started-maven-installation] * xref:ROOT:installing.adoc#getting-started.installing.java.maven[#getting-started.installing.java.maven] -* xref:ROOT:system-requirements.adoc#getting-started.system-requirements[#getting-started.system-requirements] +* xref:ROOT:installing.adoc#getting-started.installing.java[#getting-started-installation-instructions-for-java] +* xref:ROOT:installing.adoc#getting-started.installing.java[#getting-started.installing.java] +* xref:ROOT:installing.adoc#getting-started.installing[#getting-started-installing-spring-boot] +* xref:ROOT:installing.adoc#getting-started.installing[#getting-started.installing] * xref:ROOT:system-requirements.adoc#getting-started.system-requirements.graal[#getting-started.system-requirements.graal] +* xref:ROOT:system-requirements.adoc#getting-started.system-requirements.servlet-containers[#getting-started-system-requirements-servlet-containers] * xref:ROOT:system-requirements.adoc#getting-started.system-requirements.servlet-containers[#getting-started.system-requirements.servlet-containers] -* xref:ROOT:upgrading.adoc#upgrading[#upgrading] -* xref:ROOT:upgrading.adoc#upgrading[#getting-started-upgrading-from-an-earlier-version] +* xref:ROOT:system-requirements.adoc#getting-started.system-requirements[#getting-started-system-requirements] +* xref:ROOT:system-requirements.adoc#getting-started.system-requirements[#getting-started.system-requirements] * xref:ROOT:upgrading.adoc#upgrading.cli[#upgrading.cli] * xref:ROOT:upgrading.adoc#upgrading.from-1x[#upgrading.from-1x] * xref:ROOT:upgrading.adoc#upgrading.to-feature[#upgrading.to-feature] -* xref:api:rest/actuator/auditevents.adoc#audit-events[actuator-api#audit-events] -* xref:api:rest/actuator/auditevents.adoc#audit-events.retrieving[actuator-api#audit-events.retrieving] +* xref:ROOT:upgrading.adoc#upgrading[#getting-started-upgrading-from-an-earlier-version] +* xref:ROOT:upgrading.adoc#upgrading[#getting-started.installing.upgrading] +* xref:ROOT:upgrading.adoc#upgrading[#upgrading] * xref:api:rest/actuator/auditevents.adoc#audit-events.retrieving.query-parameters[actuator-api#audit-events.retrieving.query-parameters] * xref:api:rest/actuator/auditevents.adoc#audit-events.retrieving.response-structure[actuator-api#audit-events.retrieving.response-structure] -* xref:api:rest/actuator/beans.adoc#beans[actuator-api#beans] -* xref:api:rest/actuator/beans.adoc#beans.retrieving[actuator-api#beans.retrieving] +* xref:api:rest/actuator/auditevents.adoc#audit-events.retrieving[actuator-api#audit-events.retrieving] +* xref:api:rest/actuator/auditevents.adoc#audit-events[actuator-api#audit-events] * xref:api:rest/actuator/beans.adoc#beans.retrieving.response-structure[actuator-api#beans.retrieving.response-structure] -* xref:api:rest/actuator/caches.adoc#caches[actuator-api#caches] -* xref:api:rest/actuator/caches.adoc#caches.all[actuator-api#caches.all] +* xref:api:rest/actuator/beans.adoc#beans.retrieving[actuator-api#beans.retrieving] +* xref:api:rest/actuator/beans.adoc#beans[actuator-api#beans] * xref:api:rest/actuator/caches.adoc#caches.all.response-structure[actuator-api#caches.all.response-structure] +* xref:api:rest/actuator/caches.adoc#caches.all[actuator-api#caches.all] * xref:api:rest/actuator/caches.adoc#caches.evict-all[actuator-api#caches.evict-all] -* xref:api:rest/actuator/caches.adoc#caches.evict-named[actuator-api#caches.evict-named] * xref:api:rest/actuator/caches.adoc#caches.evict-named.request-structure[actuator-api#caches.evict-named.request-structure] -* xref:api:rest/actuator/caches.adoc#caches.named[actuator-api#caches.named] +* xref:api:rest/actuator/caches.adoc#caches.evict-named[actuator-api#caches.evict-named] * xref:api:rest/actuator/caches.adoc#caches.named.query-parameters[actuator-api#caches.named.query-parameters] * xref:api:rest/actuator/caches.adoc#caches.named.response-structure[actuator-api#caches.named.response-structure] -* xref:api:rest/actuator/conditions.adoc#conditions[actuator-api#conditions] -* xref:api:rest/actuator/conditions.adoc#conditions.retrieving[actuator-api#conditions.retrieving] +* xref:api:rest/actuator/caches.adoc#caches.named[actuator-api#caches.named] +* xref:api:rest/actuator/caches.adoc#caches[actuator-api#caches] * xref:api:rest/actuator/conditions.adoc#conditions.retrieving.response-structure[actuator-api#conditions.retrieving.response-structure] -* xref:api:rest/actuator/configprops.adoc#configprops[actuator-api#configprops] -* xref:api:rest/actuator/configprops.adoc#configprops.retrieving[actuator-api#configprops.retrieving] -* xref:api:rest/actuator/configprops.adoc#configprops.retrieving-by-prefix[actuator-api#configprops.retrieving-by-prefix] +* xref:api:rest/actuator/conditions.adoc#conditions.retrieving[actuator-api#conditions.retrieving] +* xref:api:rest/actuator/conditions.adoc#conditions[actuator-api#conditions] * xref:api:rest/actuator/configprops.adoc#configprops.retrieving-by-prefix.response-structure[actuator-api#configprops.retrieving-by-prefix.response-structure] +* xref:api:rest/actuator/configprops.adoc#configprops.retrieving-by-prefix[actuator-api#configprops.retrieving-by-prefix] * xref:api:rest/actuator/configprops.adoc#configprops.retrieving.response-structure[actuator-api#configprops.retrieving.response-structure] -* xref:api:rest/actuator/env.adoc#env[actuator-api#env] -* xref:api:rest/actuator/env.adoc#env.entire[actuator-api#env.entire] +* xref:api:rest/actuator/configprops.adoc#configprops.retrieving[actuator-api#configprops.retrieving] +* xref:api:rest/actuator/configprops.adoc#configprops[actuator-api#configprops] * xref:api:rest/actuator/env.adoc#env.entire.response-structure[actuator-api#env.entire.response-structure] -* xref:api:rest/actuator/env.adoc#env.single-property[actuator-api#env.single-property] +* xref:api:rest/actuator/env.adoc#env.entire[actuator-api#env.entire] * xref:api:rest/actuator/env.adoc#env.single-property.response-structure[actuator-api#env.single-property.response-structure] -* xref:api:rest/actuator/flyway.adoc#flyway[actuator-api#flyway] -* xref:api:rest/actuator/flyway.adoc#flyway.retrieving[actuator-api#flyway.retrieving] +* xref:api:rest/actuator/env.adoc#env.single-property[actuator-api#env.single-property] +* xref:api:rest/actuator/env.adoc#env[actuator-api#env] * xref:api:rest/actuator/flyway.adoc#flyway.retrieving.response-structure[actuator-api#flyway.retrieving.response-structure] -* xref:api:rest/actuator/health.adoc#health[actuator-api#health] -* xref:api:rest/actuator/health.adoc#health.retrieving[actuator-api#health.retrieving] -* xref:api:rest/actuator/health.adoc#health.retrieving-component[actuator-api#health.retrieving-component] -* xref:api:rest/actuator/health.adoc#health.retrieving-component-nested[actuator-api#health.retrieving-component-nested] +* xref:api:rest/actuator/flyway.adoc#flyway.retrieving[actuator-api#flyway.retrieving] +* xref:api:rest/actuator/flyway.adoc#flyway[actuator-api#flyway] * xref:api:rest/actuator/health.adoc#health.retrieving-component-nested.response-structure[actuator-api#health.retrieving-component-nested.response-structure] +* xref:api:rest/actuator/health.adoc#health.retrieving-component-nested[actuator-api#health.retrieving-component-nested] * xref:api:rest/actuator/health.adoc#health.retrieving-component.response-structure[actuator-api#health.retrieving-component.response-structure] +* xref:api:rest/actuator/health.adoc#health.retrieving-component[actuator-api#health.retrieving-component] * xref:api:rest/actuator/health.adoc#health.retrieving.response-structure[actuator-api#health.retrieving.response-structure] -* xref:api:rest/actuator/heapdump.adoc#heapdump[actuator-api#heapdump] +* xref:api:rest/actuator/health.adoc#health.retrieving[actuator-api#health.retrieving] +* xref:api:rest/actuator/health.adoc#health[actuator-api#health] * xref:api:rest/actuator/heapdump.adoc#heapdump.retrieving[actuator-api#heapdump.retrieving] -* xref:api:rest/actuator/httpexchanges.adoc#httpexchanges[actuator-api#httpexchanges] -* xref:api:rest/actuator/httpexchanges.adoc#httpexchanges.retrieving[actuator-api#httpexchanges.retrieving] -* xref:api:rest/actuator/httpexchanges.adoc#httpexchanges.retrieving[actuator-api#http-trace-retrieving] -* xref:api:rest/actuator/httpexchanges.adoc#httpexchanges.retrieving.response-structure[actuator-api#httpexchanges.retrieving.response-structure] +* xref:api:rest/actuator/heapdump.adoc#heapdump[actuator-api#heapdump] * xref:api:rest/actuator/httpexchanges.adoc#httpexchanges.retrieving.response-structure[actuator-api#http-trace-retrieving-response-structure] -* xref:api:rest/actuator/index.adoc#overview[actuator-api#overview] +* xref:api:rest/actuator/httpexchanges.adoc#httpexchanges.retrieving.response-structure[actuator-api#httpexchanges.retrieving.response-structure] +* xref:api:rest/actuator/httpexchanges.adoc#httpexchanges.retrieving[actuator-api#http-trace-retrieving] +* xref:api:rest/actuator/httpexchanges.adoc#httpexchanges.retrieving[actuator-api#httpexchanges.retrieving] +* xref:api:rest/actuator/httpexchanges.adoc#httpexchanges[actuator-api#httpexchanges] * xref:api:rest/actuator/index.adoc#overview.endpoint-urls[actuator-api#overview.endpoint-urls] * xref:api:rest/actuator/index.adoc#overview.timestamps[actuator-api#overview.timestamps] -* xref:api:rest/actuator/info.adoc#info[actuator-api#info] -* xref:api:rest/actuator/info.adoc#info.retrieving[actuator-api#info.retrieving] -* xref:api:rest/actuator/info.adoc#info.retrieving.response-structure[actuator-api#info.retrieving.response-structure] +* xref:api:rest/actuator/index.adoc#overview[actuator-api#overview] * xref:api:rest/actuator/info.adoc#info.retrieving.response-structure.build[actuator-api#info.retrieving.response-structure.build] * xref:api:rest/actuator/info.adoc#info.retrieving.response-structure.git[actuator-api#info.retrieving.response-structure.git] -* xref:api:rest/actuator/integrationgraph.adoc#integrationgraph[actuator-api#integrationgraph] +* xref:api:rest/actuator/info.adoc#info.retrieving.response-structure[actuator-api#info.retrieving.response-structure] +* xref:api:rest/actuator/info.adoc#info.retrieving[actuator-api#info.retrieving] +* xref:api:rest/actuator/info.adoc#info[actuator-api#info] * xref:api:rest/actuator/integrationgraph.adoc#integrationgraph.rebuilding[actuator-api#integrationgraph.rebuilding] -* xref:api:rest/actuator/integrationgraph.adoc#integrationgraph.retrieving[actuator-api#integrationgraph.retrieving] * xref:api:rest/actuator/integrationgraph.adoc#integrationgraph.retrieving.response-structure[actuator-api#integrationgraph.retrieving.response-structure] -* xref:api:rest/actuator/liquibase.adoc#liquibase[actuator-api#liquibase] -* xref:api:rest/actuator/liquibase.adoc#liquibase.retrieving[actuator-api#liquibase.retrieving] +* xref:api:rest/actuator/integrationgraph.adoc#integrationgraph.retrieving[actuator-api#integrationgraph.retrieving] +* xref:api:rest/actuator/integrationgraph.adoc#integrationgraph[actuator-api#integrationgraph] * xref:api:rest/actuator/liquibase.adoc#liquibase.retrieving.response-structure[actuator-api#liquibase.retrieving.response-structure] -* xref:api:rest/actuator/logfile.adoc#logfile[actuator-api#logfile] -* xref:api:rest/actuator/logfile.adoc#logfile.retrieving[actuator-api#logfile.retrieving] +* xref:api:rest/actuator/liquibase.adoc#liquibase.retrieving[actuator-api#liquibase.retrieving] +* xref:api:rest/actuator/liquibase.adoc#liquibase[actuator-api#liquibase] * xref:api:rest/actuator/logfile.adoc#logfile.retrieving-part[actuator-api#logfile.retrieving-part] -* xref:api:rest/actuator/loggers.adoc#loggers[actuator-api#loggers] -* xref:api:rest/actuator/loggers.adoc#loggers.all[actuator-api#loggers.all] +* xref:api:rest/actuator/logfile.adoc#logfile.retrieving[actuator-api#logfile.retrieving] +* xref:api:rest/actuator/logfile.adoc#logfile[actuator-api#logfile] * xref:api:rest/actuator/loggers.adoc#loggers.all.response-structure[actuator-api#loggers.all.response-structure] +* xref:api:rest/actuator/loggers.adoc#loggers.all[actuator-api#loggers.all] * xref:api:rest/actuator/loggers.adoc#loggers.clearing-level[actuator-api#loggers.clearing-level] -* xref:api:rest/actuator/loggers.adoc#loggers.group[actuator-api#loggers.group] -* xref:api:rest/actuator/loggers.adoc#loggers.group-setting-level[actuator-api#loggers.group-setting-level] * xref:api:rest/actuator/loggers.adoc#loggers.group-setting-level.request-structure[actuator-api#loggers.group-setting-level.request-structure] +* xref:api:rest/actuator/loggers.adoc#loggers.group-setting-level[actuator-api#loggers.group-setting-level] * xref:api:rest/actuator/loggers.adoc#loggers.group.response-structure[actuator-api#loggers.group.response-structure] -* xref:api:rest/actuator/loggers.adoc#loggers.setting-level[actuator-api#loggers.setting-level] +* xref:api:rest/actuator/loggers.adoc#loggers.group[actuator-api#loggers.group] * xref:api:rest/actuator/loggers.adoc#loggers.setting-level.request-structure[actuator-api#loggers.setting-level.request-structure] -* xref:api:rest/actuator/loggers.adoc#loggers.single[actuator-api#loggers.single] +* xref:api:rest/actuator/loggers.adoc#loggers.setting-level[actuator-api#loggers.setting-level] * xref:api:rest/actuator/loggers.adoc#loggers.single.response-structure[actuator-api#loggers.single.response-structure] -* xref:api:rest/actuator/mappings.adoc#mappings[actuator-api#mappings] -* xref:api:rest/actuator/mappings.adoc#mappings.retrieving[actuator-api#mappings.retrieving] -* xref:api:rest/actuator/mappings.adoc#mappings.retrieving.response-structure[actuator-api#mappings.retrieving.response-structure] +* xref:api:rest/actuator/loggers.adoc#loggers.single[actuator-api#loggers.single] +* xref:api:rest/actuator/loggers.adoc#loggers[actuator-api#loggers] * xref:api:rest/actuator/mappings.adoc#mappings.retrieving.response-structure-dispatcher-handlers[actuator-api#mappings.retrieving.response-structure-dispatcher-handlers] * xref:api:rest/actuator/mappings.adoc#mappings.retrieving.response-structure-dispatcher-servlets[actuator-api#mappings.retrieving.response-structure-dispatcher-servlets] * xref:api:rest/actuator/mappings.adoc#mappings.retrieving.response-structure-servlet-filters[actuator-api#mappings.retrieving.response-structure-servlet-filters] * xref:api:rest/actuator/mappings.adoc#mappings.retrieving.response-structure-servlets[actuator-api#mappings.retrieving.response-structure-servlets] -* xref:api:rest/actuator/metrics.adoc#metrics[actuator-api#metrics] +* xref:api:rest/actuator/mappings.adoc#mappings.retrieving.response-structure[actuator-api#mappings.retrieving.response-structure] +* xref:api:rest/actuator/mappings.adoc#mappings.retrieving[actuator-api#mappings.retrieving] +* xref:api:rest/actuator/mappings.adoc#mappings[actuator-api#mappings] * xref:api:rest/actuator/metrics.adoc#metrics.drilling-down[actuator-api#metrics.drilling-down] -* xref:api:rest/actuator/metrics.adoc#metrics.retrieving-metric[actuator-api#metrics.retrieving-metric] * xref:api:rest/actuator/metrics.adoc#metrics.retrieving-metric.query-parameters[actuator-api#metrics.retrieving-metric.query-parameters] * xref:api:rest/actuator/metrics.adoc#metrics.retrieving-metric.response-structure[actuator-api#metrics.retrieving-metric.response-structure] -* xref:api:rest/actuator/metrics.adoc#metrics.retrieving-names[actuator-api#metrics.retrieving-names] +* xref:api:rest/actuator/metrics.adoc#metrics.retrieving-metric[actuator-api#metrics.retrieving-metric] * xref:api:rest/actuator/metrics.adoc#metrics.retrieving-names.response-structure[actuator-api#metrics.retrieving-names.response-structure] -* xref:api:rest/actuator/prometheus.adoc#prometheus[actuator-api#prometheus] -* xref:api:rest/actuator/prometheus.adoc#prometheus.retrieving[actuator-api#prometheus.retrieving] +* xref:api:rest/actuator/metrics.adoc#metrics.retrieving-names[actuator-api#metrics.retrieving-names] +* xref:api:rest/actuator/metrics.adoc#metrics[actuator-api#metrics] * xref:api:rest/actuator/prometheus.adoc#prometheus.retrieving-names[actuator-api#prometheus.retrieving-names] * xref:api:rest/actuator/prometheus.adoc#prometheus.retrieving.query-parameters[actuator-api#prometheus.retrieving.query-parameters] -* xref:api:rest/actuator/quartz.adoc#quartz[actuator-api#quartz] -* xref:api:rest/actuator/quartz.adoc#quartz.job[actuator-api#quartz.job] -* xref:api:rest/actuator/quartz.adoc#quartz.job-group[actuator-api#quartz.job-group] +* xref:api:rest/actuator/prometheus.adoc#prometheus.retrieving[actuator-api#prometheus.retrieving] +* xref:api:rest/actuator/prometheus.adoc#prometheus[actuator-api#prometheus] * xref:api:rest/actuator/quartz.adoc#quartz.job-group.response-structure[actuator-api#quartz.job-group.response-structure] -* xref:api:rest/actuator/quartz.adoc#quartz.job-groups[actuator-api#quartz.job-groups] +* xref:api:rest/actuator/quartz.adoc#quartz.job-group[actuator-api#quartz.job-group] * xref:api:rest/actuator/quartz.adoc#quartz.job-groups.response-structure[actuator-api#quartz.job-groups.response-structure] +* xref:api:rest/actuator/quartz.adoc#quartz.job-groups[actuator-api#quartz.job-groups] * xref:api:rest/actuator/quartz.adoc#quartz.job.response-structure[actuator-api#quartz.job.response-structure] -* xref:api:rest/actuator/quartz.adoc#quartz.report[actuator-api#quartz.report] +* xref:api:rest/actuator/quartz.adoc#quartz.job[actuator-api#quartz.job] * xref:api:rest/actuator/quartz.adoc#quartz.report.response-structure[actuator-api#quartz.report.response-structure] -* xref:api:rest/actuator/quartz.adoc#quartz.trigger[actuator-api#quartz.trigger] -* xref:api:rest/actuator/quartz.adoc#quartz.trigger-group[actuator-api#quartz.trigger-group] +* xref:api:rest/actuator/quartz.adoc#quartz.report[actuator-api#quartz.report] * xref:api:rest/actuator/quartz.adoc#quartz.trigger-group.response-structure[actuator-api#quartz.trigger-group.response-structure] -* xref:api:rest/actuator/quartz.adoc#quartz.trigger-groups[actuator-api#quartz.trigger-groups] +* xref:api:rest/actuator/quartz.adoc#quartz.trigger-group[actuator-api#quartz.trigger-group] * xref:api:rest/actuator/quartz.adoc#quartz.trigger-groups.response-structure[actuator-api#quartz.trigger-groups.response-structure] +* xref:api:rest/actuator/quartz.adoc#quartz.trigger-groups[actuator-api#quartz.trigger-groups] * xref:api:rest/actuator/quartz.adoc#quartz.trigger.calendar-interval-response-structure[actuator-api#quartz.trigger.calendar-interval-response-structure] * xref:api:rest/actuator/quartz.adoc#quartz.trigger.common-response-structure[actuator-api#quartz.trigger.common-response-structure] * xref:api:rest/actuator/quartz.adoc#quartz.trigger.cron-response-structure[actuator-api#quartz.trigger.cron-response-structure] * xref:api:rest/actuator/quartz.adoc#quartz.trigger.custom-response-structure[actuator-api#quartz.trigger.custom-response-structure] * xref:api:rest/actuator/quartz.adoc#quartz.trigger.daily-time-interval-response-structure[actuator-api#quartz.trigger.daily-time-interval-response-structure] * xref:api:rest/actuator/quartz.adoc#quartz.trigger.simple-response-structure[actuator-api#quartz.trigger.simple-response-structure] -* xref:api:rest/actuator/sbom.adoc#sbom[actuator-api#sbom] -* xref:api:rest/actuator/sbom.adoc#sbom.retrieving-available-sboms[actuator-api#sbom.retrieving-available-sboms] +* xref:api:rest/actuator/quartz.adoc#quartz.trigger[actuator-api#quartz.trigger] +* xref:api:rest/actuator/quartz.adoc#quartz[actuator-api#quartz] * xref:api:rest/actuator/sbom.adoc#sbom.retrieving-available-sboms.response-structure[actuator-api#sbom.retrieving-available-sboms.response-structure] -* xref:api:rest/actuator/sbom.adoc#sbom.retrieving-single-sbom[actuator-api#sbom.retrieving-single-sbom] +* xref:api:rest/actuator/sbom.adoc#sbom.retrieving-available-sboms[actuator-api#sbom.retrieving-available-sboms] * xref:api:rest/actuator/sbom.adoc#sbom.retrieving-single-sbom.response-structure[actuator-api#sbom.retrieving-single-sbom.response-structure] -* xref:api:rest/actuator/scheduledtasks.adoc#scheduled-tasks[actuator-api#scheduled-tasks] -* xref:api:rest/actuator/scheduledtasks.adoc#scheduled-tasks.retrieving[actuator-api#scheduled-tasks.retrieving] +* xref:api:rest/actuator/sbom.adoc#sbom.retrieving-single-sbom[actuator-api#sbom.retrieving-single-sbom] +* xref:api:rest/actuator/sbom.adoc#sbom[actuator-api#sbom] * xref:api:rest/actuator/scheduledtasks.adoc#scheduled-tasks.retrieving.response-structure[actuator-api#scheduled-tasks.retrieving.response-structure] -* xref:api:rest/actuator/sessions.adoc#sessions[actuator-api#sessions] +* xref:api:rest/actuator/scheduledtasks.adoc#scheduled-tasks.retrieving[actuator-api#scheduled-tasks.retrieving] +* xref:api:rest/actuator/scheduledtasks.adoc#scheduled-tasks[actuator-api#scheduled-tasks] * xref:api:rest/actuator/sessions.adoc#sessions.deleting[actuator-api#sessions.deleting] -* xref:api:rest/actuator/sessions.adoc#sessions.retrieving[actuator-api#sessions.retrieving] -* xref:api:rest/actuator/sessions.adoc#sessions.retrieving-id[actuator-api#sessions.retrieving-id] * xref:api:rest/actuator/sessions.adoc#sessions.retrieving-id.response-structure[actuator-api#sessions.retrieving-id.response-structure] +* xref:api:rest/actuator/sessions.adoc#sessions.retrieving-id[actuator-api#sessions.retrieving-id] * xref:api:rest/actuator/sessions.adoc#sessions.retrieving.query-parameters[actuator-api#sessions.retrieving.query-parameters] * xref:api:rest/actuator/sessions.adoc#sessions.retrieving.response-structure[actuator-api#sessions.retrieving.response-structure] -* xref:api:rest/actuator/shutdown.adoc#shutdown[actuator-api#shutdown] -* xref:api:rest/actuator/shutdown.adoc#shutdown.shutting-down[actuator-api#shutdown.shutting-down] +* xref:api:rest/actuator/sessions.adoc#sessions.retrieving[actuator-api#sessions.retrieving] +* xref:api:rest/actuator/sessions.adoc#sessions[actuator-api#sessions] * xref:api:rest/actuator/shutdown.adoc#shutdown.shutting-down.response-structure[actuator-api#shutdown.shutting-down.response-structure] -* xref:api:rest/actuator/startup.adoc#startup[actuator-api#startup] -* xref:api:rest/actuator/startup.adoc#startup.retrieving[actuator-api#startup.retrieving] +* xref:api:rest/actuator/shutdown.adoc#shutdown.shutting-down[actuator-api#shutdown.shutting-down] +* xref:api:rest/actuator/shutdown.adoc#shutdown[actuator-api#shutdown] * xref:api:rest/actuator/startup.adoc#startup.retrieving.drain[actuator-api#startup.retrieving.drain] * xref:api:rest/actuator/startup.adoc#startup.retrieving.response-structure[actuator-api#startup.retrieving.response-structure] * xref:api:rest/actuator/startup.adoc#startup.retrieving.snapshot[actuator-api#startup.retrieving.snapshot] -* xref:api:rest/actuator/threaddump.adoc#threaddump[actuator-api#threaddump] -* xref:api:rest/actuator/threaddump.adoc#threaddump.retrieving-json[actuator-api#threaddump.retrieving-json] +* xref:api:rest/actuator/startup.adoc#startup.retrieving[actuator-api#startup.retrieving] +* xref:api:rest/actuator/startup.adoc#startup[actuator-api#startup] * xref:api:rest/actuator/threaddump.adoc#threaddump.retrieving-json.response-structure[actuator-api#threaddump.retrieving-json.response-structure] +* xref:api:rest/actuator/threaddump.adoc#threaddump.retrieving-json[actuator-api#threaddump.retrieving-json] * xref:api:rest/actuator/threaddump.adoc#threaddump.retrieving-text[actuator-api#threaddump.retrieving-text] -* xref:appendix:application-properties/index.adoc#appendix.application-properties[#appendix.application-properties] +* xref:api:rest/actuator/threaddump.adoc#threaddump[actuator-api#threaddump] * xref:appendix:application-properties/index.adoc#appendix.application-properties.actuator[#appendix.application-properties.actuator] +* xref:appendix:application-properties/index.adoc#appendix.application-properties.actuator[#common-application-properties-actuator] * xref:appendix:application-properties/index.adoc#appendix.application-properties.cache[#appendix.application-properties.cache] +* xref:appendix:application-properties/index.adoc#appendix.application-properties.cache[#common-application-properties-cache] * xref:appendix:application-properties/index.adoc#appendix.application-properties.core[#appendix.application-properties.core] -* xref:appendix:application-properties/index.adoc#appendix.application-properties.data[#appendix.application-properties.data] +* xref:appendix:application-properties/index.adoc#appendix.application-properties.core[#core-properties] * xref:appendix:application-properties/index.adoc#appendix.application-properties.data-migration[#appendix.application-properties.data-migration] +* xref:appendix:application-properties/index.adoc#appendix.application-properties.data-migration[#data-migration-properties] +* xref:appendix:application-properties/index.adoc#appendix.application-properties.data[#appendix.application-properties.data] +* xref:appendix:application-properties/index.adoc#appendix.application-properties.data[#data-properties] * xref:appendix:application-properties/index.adoc#appendix.application-properties.devtools[#appendix.application-properties.devtools] +* xref:appendix:application-properties/index.adoc#appendix.application-properties.devtools[#devtools-properties] * xref:appendix:application-properties/index.adoc#appendix.application-properties.docker-compose[#appendix.application-properties.docker-compose] * xref:appendix:application-properties/index.adoc#appendix.application-properties.integration[#appendix.application-properties.integration] +* xref:appendix:application-properties/index.adoc#appendix.application-properties.integration[#integration-properties] * xref:appendix:application-properties/index.adoc#appendix.application-properties.json[#appendix.application-properties.json] +* xref:appendix:application-properties/index.adoc#appendix.application-properties.json[#json-properties] * xref:appendix:application-properties/index.adoc#appendix.application-properties.mail[#appendix.application-properties.mail] +* xref:appendix:application-properties/index.adoc#appendix.application-properties.mail[#mail-properties] * xref:appendix:application-properties/index.adoc#appendix.application-properties.rsocket[#appendix.application-properties.rsocket] +* xref:appendix:application-properties/index.adoc#appendix.application-properties.rsocket[#rsocket-properties] * xref:appendix:application-properties/index.adoc#appendix.application-properties.security[#appendix.application-properties.security] +* xref:appendix:application-properties/index.adoc#appendix.application-properties.security[#security-properties] * xref:appendix:application-properties/index.adoc#appendix.application-properties.server[#appendix.application-properties.server] +* xref:appendix:application-properties/index.adoc#appendix.application-properties.server[#server-properties] * xref:appendix:application-properties/index.adoc#appendix.application-properties.templating[#appendix.application-properties.templating] +* xref:appendix:application-properties/index.adoc#appendix.application-properties.templating[#templating-properties] * xref:appendix:application-properties/index.adoc#appendix.application-properties.testcontainers[#appendix.application-properties.testcontainers] * xref:appendix:application-properties/index.adoc#appendix.application-properties.testing[#appendix.application-properties.testing] +* xref:appendix:application-properties/index.adoc#appendix.application-properties.testing[#testing-properties] * xref:appendix:application-properties/index.adoc#appendix.application-properties.transaction[#appendix.application-properties.transaction] +* xref:appendix:application-properties/index.adoc#appendix.application-properties.transaction[#transaction-properties] * xref:appendix:application-properties/index.adoc#appendix.application-properties.web[#appendix.application-properties.web] +* xref:appendix:application-properties/index.adoc#appendix.application-properties.web[#web-properties] +* xref:appendix:application-properties/index.adoc#appendix.application-properties[#appendix.application-properties] +* xref:appendix:application-properties/index.adoc#appendix.application-properties[#common-application-properties] +* xref:appendix:application-properties/index.adoc[#application-properties] +* xref:appendix:application-properties/index.adoc[application-properties] * xref:appendix:auto-configuration-classes/actuator.adoc#appendix.auto-configuration-classes.actuator[#appendix.auto-configuration-classes.actuator] +* xref:appendix:auto-configuration-classes/actuator.adoc#appendix.auto-configuration-classes.actuator[#auto-configuration-classes.actuator] * xref:appendix:auto-configuration-classes/core.adoc#appendix.auto-configuration-classes.core[#appendix.auto-configuration-classes.core] +* xref:appendix:auto-configuration-classes/core.adoc#appendix.auto-configuration-classes.core[#auto-configuration-classes.core] * xref:appendix:auto-configuration-classes/index.adoc#appendix.auto-configuration-classes[#appendix.auto-configuration-classes] +* xref:appendix:auto-configuration-classes/index.adoc#appendix.auto-configuration-classes[#auto-configuration-classes] +* xref:appendix:auto-configuration-classes/index.adoc[#auto-configuration-classes] +* xref:appendix:auto-configuration-classes/index.adoc[auto-configuration-classes] * xref:appendix:dependency-versions/coordinates.adoc#appendix.dependency-versions.coordinates[#appendix.dependency-versions.coordinates] +* xref:appendix:dependency-versions/coordinates.adoc#appendix.dependency-versions.coordinates[#dependency-versions.coordinates] * xref:appendix:dependency-versions/index.adoc#appendix.dependency-versions[#appendix.dependency-versions] +* xref:appendix:dependency-versions/index.adoc#appendix.dependency-versions[#dependency-versions] +* xref:appendix:dependency-versions/index.adoc[#dependency-versions] +* xref:appendix:dependency-versions/index.adoc[dependency-versions] * xref:appendix:dependency-versions/properties.adoc#appendix.dependency-versions.properties[#appendix.dependency-versions.properties] +* xref:appendix:dependency-versions/properties.adoc#appendix.dependency-versions.properties[#dependency-versions.properties] * xref:appendix:test-auto-configuration/index.adoc#appendix.test-auto-configuration[#appendix.test-auto-configuration] +* xref:appendix:test-auto-configuration/index.adoc#appendix.test-auto-configuration[#test-auto-configuration] +* xref:appendix:test-auto-configuration/index.adoc[#test-auto-configuration] +* xref:appendix:test-auto-configuration/index.adoc[test-auto-configuration] * xref:appendix:test-auto-configuration/slices.adoc#appendix.test-auto-configuration.slices[#appendix.test-auto-configuration.slices] -* xref:build-tool-plugin:antlib.adoc#build-tool-plugins.antlib[#build-tool-plugins.antlib] -* xref:build-tool-plugin:antlib.adoc#build-tool-plugins.antlib.findmainclass[#build-tool-plugins.antlib.findmainclass] +* xref:appendix:test-auto-configuration/slices.adoc#appendix.test-auto-configuration.slices[#test-auto-configuration.slices] * xref:build-tool-plugin:antlib.adoc#build-tool-plugins.antlib.findmainclass.examples[#build-tool-plugins.antlib.findmainclass.examples] -* xref:build-tool-plugin:antlib.adoc#build-tool-plugins.antlib.tasks[#build-tool-plugins.antlib.tasks] +* xref:build-tool-plugin:antlib.adoc#build-tool-plugins.antlib.findmainclass.examples[#spring-boot-ant-findmainclass-examples] +* xref:build-tool-plugin:antlib.adoc#build-tool-plugins.antlib.findmainclass[#build-tool-plugins.antlib.findmainclass] +* xref:build-tool-plugin:antlib.adoc#build-tool-plugins.antlib.findmainclass[#spring-boot-ant-findmainclass] * xref:build-tool-plugin:antlib.adoc#build-tool-plugins.antlib.tasks.examples[#build-tool-plugins.antlib.tasks.examples] +* xref:build-tool-plugin:antlib.adoc#build-tool-plugins.antlib.tasks.examples[#spring-boot-ant-exejar-examples] * xref:build-tool-plugin:antlib.adoc#build-tool-plugins.antlib.tasks.exejar[#build-tool-plugins.antlib.tasks.exejar] +* xref:build-tool-plugin:antlib.adoc#build-tool-plugins.antlib.tasks.exejar[#spring-boot-ant-exejar] +* xref:build-tool-plugin:antlib.adoc#build-tool-plugins.antlib.tasks[#build-tool-plugins.antlib.tasks] +* xref:build-tool-plugin:antlib.adoc#build-tool-plugins.antlib.tasks[#spring-boot-ant-tasks] +* xref:build-tool-plugin:antlib.adoc#build-tool-plugins.antlib[#build-tool-plugins-antlib] +* xref:build-tool-plugin:antlib.adoc#build-tool-plugins.antlib[#build-tool-plugins.antlib] * xref:build-tool-plugin:index.adoc#build-tool-plugins[#build-tool-plugins] -* xref:build-tool-plugin:other-build-systems.adoc#build-tool-plugins.other-build-systems[#build-tool-plugins.other-build-systems] +* xref:build-tool-plugin:index.adoc[#build-tool-plugins] +* xref:build-tool-plugin:index.adoc[build-tool-plugins] +* xref:build-tool-plugin:other-build-systems.adoc#build-tool-plugins.other-build-systems.example-repackage-implementation[#build-tool-plugins-repackage-implementation] * xref:build-tool-plugin:other-build-systems.adoc#build-tool-plugins.other-build-systems.example-repackage-implementation[#build-tool-plugins.other-build-systems.example-repackage-implementation] +* xref:build-tool-plugin:other-build-systems.adoc#build-tool-plugins.other-build-systems.finding-main-class[#build-tool-plugins-find-a-main-class] * xref:build-tool-plugin:other-build-systems.adoc#build-tool-plugins.other-build-systems.finding-main-class[#build-tool-plugins.other-build-systems.finding-main-class] +* xref:build-tool-plugin:other-build-systems.adoc#build-tool-plugins.other-build-systems.nested-libraries[#build-tool-plugins-nested-libraries] * xref:build-tool-plugin:other-build-systems.adoc#build-tool-plugins.other-build-systems.nested-libraries[#build-tool-plugins.other-build-systems.nested-libraries] +* xref:build-tool-plugin:other-build-systems.adoc#build-tool-plugins.other-build-systems.repackaging-archives[#build-tool-plugins-repackaging-archives] * xref:build-tool-plugin:other-build-systems.adoc#build-tool-plugins.other-build-systems.repackaging-archives[#build-tool-plugins.other-build-systems.repackaging-archives] +* xref:build-tool-plugin:other-build-systems.adoc#build-tool-plugins.other-build-systems[#build-tool-plugins-other-build-systems] +* xref:build-tool-plugin:other-build-systems.adoc#build-tool-plugins.other-build-systems[#build-tool-plugins.other-build-systems] * xref:cli:index.adoc#cli[#cli] +* xref:cli:index.adoc[#cli] +* xref:cli:index.adoc[cli] +* xref:cli:installation.adoc#cli.installation[#cli-installation] * xref:cli:installation.adoc#cli.installation[#cli.installation] -* xref:cli:using-the-cli.adoc#cli.using-the-cli[#cli.using-the-cli] +* xref:cli:using-the-cli.adoc#cli.using-the-cli.embedded-shell[#cli-shell] * xref:cli:using-the-cli.adoc#cli.using-the-cli.embedded-shell[#cli.using-the-cli.embedded-shell] +* xref:cli:using-the-cli.adoc#cli.using-the-cli.initialize-new-project[#cli-init] * xref:cli:using-the-cli.adoc#cli.using-the-cli.initialize-new-project[#cli.using-the-cli.initialize-new-project] -* xref:gradle-plugin:aot.adoc#aot[gradle-plugin#aot] +* xref:cli:using-the-cli.adoc#cli.using-the-cli[#cli-using-the-cli] +* xref:cli:using-the-cli.adoc#cli.using-the-cli[#cli.using-the-cli] +* xref:community.adoc[#boot-documentation-getting-help] +* xref:community.adoc[#documentation.getting-help] +* xref:community.adoc[#getting-help] +* xref:community.adoc[getting-help] +* xref:documentation.adoc[#boot-documentation-about] +* xref:documentation.adoc[#documentation.about] +* xref:documentation.adoc[#documentation] +* xref:documentation.adoc[documentation] * xref:gradle-plugin:aot.adoc#aot.processing-applications[gradle-plugin#aot.processing-applications] * xref:gradle-plugin:aot.adoc#aot.processing-tests[gradle-plugin#aot.processing-tests] +* xref:gradle-plugin:aot.adoc#aot[gradle-plugin#aot] * xref:gradle-plugin:getting-started.adoc#getting-started[gradle-plugin#getting-started] * xref:gradle-plugin:index.adoc#gradle-plugin[gradle-plugin#gradle-plugin] -* xref:gradle-plugin:integrating-with-actuator.adoc#integrating-with-actuator[gradle-plugin#integrating-with-actuator] * xref:gradle-plugin:integrating-with-actuator.adoc#integrating-with-actuator.build-info[gradle-plugin#integrating-with-actuator.build-info] +* xref:gradle-plugin:integrating-with-actuator.adoc#integrating-with-actuator[gradle-plugin#integrating-with-actuator] * xref:gradle-plugin:introduction.adoc#introduction[gradle-plugin#introduction] -* xref:gradle-plugin:managing-dependencies.adoc#managing-dependencies[gradle-plugin#managing-dependencies] -* xref:gradle-plugin:managing-dependencies.adoc#managing-dependencies.dependency-management-plugin[gradle-plugin#managing-dependencies.dependency-management-plugin] * xref:gradle-plugin:managing-dependencies.adoc#managing-dependencies.dependency-management-plugin.customizing[gradle-plugin#managing-dependencies.dependency-management-plugin.customizing] * xref:gradle-plugin:managing-dependencies.adoc#managing-dependencies.dependency-management-plugin.learning-more[gradle-plugin#managing-dependencies.dependency-management-plugin.learning-more] * xref:gradle-plugin:managing-dependencies.adoc#managing-dependencies.dependency-management-plugin.using-in-isolation[gradle-plugin#managing-dependencies.dependency-management-plugin.using-in-isolation] -* xref:gradle-plugin:managing-dependencies.adoc#managing-dependencies.gradle-bom-support[gradle-plugin#managing-dependencies.gradle-bom-support] +* xref:gradle-plugin:managing-dependencies.adoc#managing-dependencies.dependency-management-plugin[gradle-plugin#managing-dependencies.dependency-management-plugin] * xref:gradle-plugin:managing-dependencies.adoc#managing-dependencies.gradle-bom-support.customizing[gradle-plugin#managing-dependencies.gradle-bom-support.customizing] -* xref:gradle-plugin:packaging-oci-image.adoc#build-image[gradle-plugin#build-image] -* xref:gradle-plugin:packaging-oci-image.adoc#build-image.customization[gradle-plugin#build-image.customization] +* xref:gradle-plugin:managing-dependencies.adoc#managing-dependencies.gradle-bom-support[gradle-plugin#managing-dependencies.gradle-bom-support] +* xref:gradle-plugin:managing-dependencies.adoc#managing-dependencies[gradle-plugin#managing-dependencies] * xref:gradle-plugin:packaging-oci-image.adoc#build-image.customization.tags[gradle-plugin#build-image.customization.tags] +* xref:gradle-plugin:packaging-oci-image.adoc#build-image.customization[gradle-plugin#build-image.customization] * xref:gradle-plugin:packaging-oci-image.adoc#build-image.docker-daemon[gradle-plugin#build-image.docker-daemon] * xref:gradle-plugin:packaging-oci-image.adoc#build-image.docker-registry[gradle-plugin#build-image.docker-registry] -* xref:gradle-plugin:packaging-oci-image.adoc#build-image.examples[gradle-plugin#build-image.examples] * xref:gradle-plugin:packaging-oci-image.adoc#build-image.examples.builder-configuration[gradle-plugin#build-image.examples.builder-configuration] * xref:gradle-plugin:packaging-oci-image.adoc#build-image.examples.buildpacks[gradle-plugin#build-image.examples.buildpacks] * xref:gradle-plugin:packaging-oci-image.adoc#build-image.examples.caches[gradle-plugin#build-image.examples.caches] * xref:gradle-plugin:packaging-oci-image.adoc#build-image.examples.custom-image-builder[gradle-plugin#build-image.examples.custom-image-builder] * xref:gradle-plugin:packaging-oci-image.adoc#build-image.examples.custom-image-name[gradle-plugin#build-image.examples.custom-image-name] -* xref:gradle-plugin:packaging-oci-image.adoc#build-image.examples.docker[gradle-plugin#build-image.examples.docker] * xref:gradle-plugin:packaging-oci-image.adoc#build-image.examples.docker.auth[gradle-plugin#build-image.examples.docker.auth] * xref:gradle-plugin:packaging-oci-image.adoc#build-image.examples.docker.colima[gradle-plugin#build-image.examples.docker.colima] * xref:gradle-plugin:packaging-oci-image.adoc#build-image.examples.docker.minikube[gradle-plugin#build-image.examples.docker.minikube] * xref:gradle-plugin:packaging-oci-image.adoc#build-image.examples.docker.podman[gradle-plugin#build-image.examples.docker.podman] +* xref:gradle-plugin:packaging-oci-image.adoc#build-image.examples.docker[gradle-plugin#build-image.examples.docker] * xref:gradle-plugin:packaging-oci-image.adoc#build-image.examples.publish[gradle-plugin#build-image.examples.publish] * xref:gradle-plugin:packaging-oci-image.adoc#build-image.examples.runtime-jvm-configuration[gradle-plugin#build-image.examples.runtime-jvm-configuration] -* xref:gradle-plugin:packaging.adoc#packaging-executable[gradle-plugin#packaging-executable] +* xref:gradle-plugin:packaging-oci-image.adoc#build-image.examples[gradle-plugin#build-image.examples] +* xref:gradle-plugin:packaging-oci-image.adoc#build-image[gradle-plugin#build-image] * xref:gradle-plugin:packaging.adoc#packaging-executable.and-plain-archives[gradle-plugin#packaging-executable.and-plain-archives] -* xref:gradle-plugin:packaging.adoc#packaging-executable.configuring[gradle-plugin#packaging-executable.configuring] * xref:gradle-plugin:packaging.adoc#packaging-executable.configuring.including-development-only-dependencies[gradle-plugin#packaging-executable.configuring.including-development-only-dependencies] * xref:gradle-plugin:packaging.adoc#packaging-executable.configuring.launch-script[gradle-plugin#packaging-executable.configuring.launch-script] -* xref:gradle-plugin:packaging.adoc#packaging-executable.configuring.layered-archives[gradle-plugin#packaging-executable.configuring.layered-archives] * xref:gradle-plugin:packaging.adoc#packaging-executable.configuring.layered-archives.configuration[gradle-plugin#packaging-executable.configuring.layered-archives.configuration] +* xref:gradle-plugin:packaging.adoc#packaging-executable.configuring.layered-archives[gradle-plugin#packaging-executable.configuring.layered-archives] * xref:gradle-plugin:packaging.adoc#packaging-executable.configuring.main-class[gradle-plugin#packaging-executable.configuring.main-class] * xref:gradle-plugin:packaging.adoc#packaging-executable.configuring.properties-launcher[gradle-plugin#packaging-executable.configuring.properties-launcher] * xref:gradle-plugin:packaging.adoc#packaging-executable.configuring.unpacking[gradle-plugin#packaging-executable.configuring.unpacking] +* xref:gradle-plugin:packaging.adoc#packaging-executable.configuring[gradle-plugin#packaging-executable.configuring] * xref:gradle-plugin:packaging.adoc#packaging-executable.jars[gradle-plugin#packaging-executable.jars] -* xref:gradle-plugin:packaging.adoc#packaging-executable.wars[gradle-plugin#packaging-executable.wars] * xref:gradle-plugin:packaging.adoc#packaging-executable.wars.deployable[gradle-plugin#packaging-executable.wars.deployable] -* xref:gradle-plugin:publishing.adoc#publishing-your-application[gradle-plugin#publishing-your-application] +* xref:gradle-plugin:packaging.adoc#packaging-executable.wars[gradle-plugin#packaging-executable.wars] +* xref:gradle-plugin:packaging.adoc#packaging-executable[gradle-plugin#packaging-executable] * xref:gradle-plugin:publishing.adoc#publishing-your-application.distribution[gradle-plugin#publishing-your-application.distribution] * xref:gradle-plugin:publishing.adoc#publishing-your-application.maven-publish[gradle-plugin#publishing-your-application-maven] * xref:gradle-plugin:publishing.adoc#publishing-your-application.maven-publish[gradle-plugin#publishing-your-application.maven-publish] -* xref:gradle-plugin:reacting.adoc#reacting-to-other-plugins[gradle-plugin#reacting-to-other-plugins] +* xref:gradle-plugin:publishing.adoc#publishing-your-application[gradle-plugin#publishing-your-application] * xref:gradle-plugin:reacting.adoc#reacting-to-other-plugins.application[gradle-plugin#reacting-to-other-plugins.application] * xref:gradle-plugin:reacting.adoc#reacting-to-other-plugins.dependency-management[gradle-plugin#reacting-to-other-plugins.dependency-management] * xref:gradle-plugin:reacting.adoc#reacting-to-other-plugins.java[gradle-plugin#reacting-to-other-plugins.java] * xref:gradle-plugin:reacting.adoc#reacting-to-other-plugins.kotlin[gradle-plugin#reacting-to-other-plugins.kotlin] * xref:gradle-plugin:reacting.adoc#reacting-to-other-plugins.nbt[gradle-plugin#reacting-to-other-plugins.nbt] * xref:gradle-plugin:reacting.adoc#reacting-to-other-plugins.war[gradle-plugin#reacting-to-other-plugins.war] -* xref:gradle-plugin:running.adoc#running-your-application[gradle-plugin#running-your-application] +* xref:gradle-plugin:reacting.adoc#reacting-to-other-plugins[gradle-plugin#reacting-to-other-plugins] * xref:gradle-plugin:running.adoc#running-your-application.passing-arguments[gradle-plugin#running-your-application.passing-arguments] * xref:gradle-plugin:running.adoc#running-your-application.passing-system-properties[gradle-plugin#running-your-application.passing-system-properties] * xref:gradle-plugin:running.adoc#running-your-application.reloading-resources[gradle-plugin#running-your-application.reloading-resources] * xref:gradle-plugin:running.adoc#running-your-application.using-a-test-main-class[gradle-plugin#running-your-application.using-a-test-main-class] -* xref:how-to:actuator.adoc#howto.actuator[#howto.actuator] +* xref:gradle-plugin:running.adoc#running-your-application[gradle-plugin#running-your-application] +* xref:how-to:actuator.adoc#howto.actuator.change-http-port-or-address[#howto-change-the-http-port-or-address-of-the-actuator-endpoints] * xref:how-to:actuator.adoc#howto.actuator.change-http-port-or-address[#howto.actuator.change-http-port-or-address] * xref:how-to:actuator.adoc#howto.actuator.customizing-sanitization[#howto.actuator.customizing-sanitization] +* xref:how-to:actuator.adoc#howto.actuator.customizing-sanitization[#howto.actuator.sanitize-sensitive-values.customizing-sanitization] +* xref:how-to:actuator.adoc#howto.actuator.map-health-indicators-to-metrics[#howto-map-health-indicators-to-metrics] * xref:how-to:actuator.adoc#howto.actuator.map-health-indicators-to-metrics[#howto.actuator.map-health-indicators-to-metrics] -* xref:how-to:aot.adoc#howto.aot[#howto.aot] +* xref:how-to:actuator.adoc#howto.actuator[#howto-actuator] +* xref:how-to:actuator.adoc#howto.actuator[#howto.actuator] * xref:how-to:aot.adoc#howto.aot.conditions[#howto.aot.conditions] -* xref:how-to:application.adoc#howto.application[#howto.application] +* xref:how-to:aot.adoc#howto.aot[#howto.aot] +* xref:how-to:application.adoc#howto.application.context-hierarchy[#howto-build-an-application-context-hierarchy] * xref:how-to:application.adoc#howto.application.context-hierarchy[#howto.application.context-hierarchy] +* xref:how-to:application.adoc#howto.application.customize-the-environment-or-application-context[#howto-customize-the-environment-or-application-context] * xref:how-to:application.adoc#howto.application.customize-the-environment-or-application-context[#howto.application.customize-the-environment-or-application-context] +* xref:how-to:application.adoc#howto.application.failure-analyzer[#howto-failure-analyzer] * xref:how-to:application.adoc#howto.application.failure-analyzer[#howto.application.failure-analyzer] +* xref:how-to:application.adoc#howto.application.non-web-application[#howto-create-a-non-web-application] * xref:how-to:application.adoc#howto.application.non-web-application[#howto.application.non-web-application] +* xref:how-to:application.adoc#howto.application.troubleshoot-auto-configuration[#howto-troubleshoot-auto-configuration] * xref:how-to:application.adoc#howto.application.troubleshoot-auto-configuration[#howto.application.troubleshoot-auto-configuration] -* xref:how-to:batch.adoc#howto.batch[#howto.batch] +* xref:how-to:application.adoc#howto.application[#howto-spring-boot-application] +* xref:how-to:application.adoc#howto.application[#howto.application] * xref:how-to:batch.adoc#howto.batch.restarting-a-failed-job[#howto.batch.restarting-a-failed-job] +* xref:how-to:batch.adoc#howto.batch.running-from-the-command-line[#howto-spring-batch-running-command-line] * xref:how-to:batch.adoc#howto.batch.running-from-the-command-line[#howto.batch.running-from-the-command-line] +* xref:how-to:batch.adoc#howto.batch.running-jobs-on-startup[#howto-spring-batch-running-jobs-on-startup] * xref:how-to:batch.adoc#howto.batch.running-jobs-on-startup[#howto.batch.running-jobs-on-startup] +* xref:how-to:batch.adoc#howto.batch.specifying-a-data-source[#howto-spring-batch-specifying-a-data-source] * xref:how-to:batch.adoc#howto.batch.specifying-a-data-source[#howto.batch.specifying-a-data-source] * xref:how-to:batch.adoc#howto.batch.specifying-a-transaction-manager[#howto.batch.specifying-a-transaction-manager] +* xref:how-to:batch.adoc#howto.batch.storing-job-repository[#howto-spring-batch-storing-job-repository] * xref:how-to:batch.adoc#howto.batch.storing-job-repository[#howto.batch.storing-job-repository] -* xref:how-to:build.adoc#howto.build[#howto.build] +* xref:how-to:batch.adoc#howto.batch[#howto-batch-applications] +* xref:how-to:batch.adoc#howto.batch[#howto.batch] +* xref:how-to:build.adoc#howto.build.build-an-executable-archive-with-ant-without-using-spring-boot-antlib[#howto-build-an-executable-archive-with-ant] * xref:how-to:build.adoc#howto.build.build-an-executable-archive-with-ant-without-using-spring-boot-antlib[#howto.build.build-an-executable-archive-with-ant-without-using-spring-boot-antlib] +* xref:how-to:build.adoc#howto.build.create-a-nonexecutable-jar[#howto-create-a-nonexecutable-jar] * xref:how-to:build.adoc#howto.build.create-a-nonexecutable-jar[#howto.build.create-a-nonexecutable-jar] +* xref:how-to:build.adoc#howto.build.create-an-executable-jar-with-maven[#howto-create-an-executable-jar-with-maven] * xref:how-to:build.adoc#howto.build.create-an-executable-jar-with-maven[#howto.build.create-an-executable-jar-with-maven] +* xref:how-to:build.adoc#howto.build.customize-dependency-versions[#howto-customize-dependency-versions] * xref:how-to:build.adoc#howto.build.customize-dependency-versions[#howto.build.customize-dependency-versions] +* xref:how-to:build.adoc#howto.build.extract-specific-libraries-when-an-executable-jar-runs[#howto-extract-specific-libraries-when-an-executable-jar-runs] * xref:how-to:build.adoc#howto.build.extract-specific-libraries-when-an-executable-jar-runs[#howto.build.extract-specific-libraries-when-an-executable-jar-runs] +* xref:how-to:build.adoc#howto.build.generate-git-info[#howto-git-info] * xref:how-to:build.adoc#howto.build.generate-git-info[#howto.build.generate-git-info] +* xref:how-to:build.adoc#howto.build.generate-info[#howto-build-info] * xref:how-to:build.adoc#howto.build.generate-info[#howto.build.generate-info] +* xref:how-to:build.adoc#howto.build.remote-debug-maven[#howto-remote-debug-maven-run] * xref:how-to:build.adoc#howto.build.remote-debug-maven[#howto.build.remote-debug-maven] +* xref:how-to:build.adoc#howto.build.use-a-spring-boot-application-as-dependency[#howto-create-an-additional-executable-jar] * xref:how-to:build.adoc#howto.build.use-a-spring-boot-application-as-dependency[#howto.build.use-a-spring-boot-application-as-dependency] -* xref:how-to:data-access.adoc#howto.data-access[#howto.data-access] +* xref:how-to:build.adoc#howto.build[#howto-build] +* xref:how-to:build.adoc#howto.build[#howto.build] +* xref:how-to:data-access.adoc#howto.data-access.configure-a-component-that-is-used-by-jpa[#howto-configure-a-component-that-is-used-by-JPA] * xref:how-to:data-access.adoc#howto.data-access.configure-a-component-that-is-used-by-jpa[#howto.data-access.configure-a-component-that-is-used-by-jpa] +* xref:how-to:data-access.adoc#howto.data-access.configure-custom-datasource[#howto-configure-a-datasource] * xref:how-to:data-access.adoc#howto.data-access.configure-custom-datasource[#howto.data-access.configure-custom-datasource] +* xref:how-to:data-access.adoc#howto.data-access.configure-hibernate-naming-strategy[#howto-configure-hibernate-naming-strategy] * xref:how-to:data-access.adoc#howto.data-access.configure-hibernate-naming-strategy[#howto.data-access.configure-hibernate-naming-strategy] +* xref:how-to:data-access.adoc#howto.data-access.configure-hibernate-second-level-caching[#howto-configure-hibernate-second-level-caching] * xref:how-to:data-access.adoc#howto.data-access.configure-hibernate-second-level-caching[#howto.data-access.configure-hibernate-second-level-caching] +* xref:how-to:data-access.adoc#howto.data-access.configure-jooq-with-multiple-datasources[#howto-configure-jOOQ-with-multiple-datasources] * xref:how-to:data-access.adoc#howto.data-access.configure-jooq-with-multiple-datasources[#howto.data-access.configure-jooq-with-multiple-datasources] +* xref:how-to:data-access.adoc#howto.data-access.configure-two-datasources[#howto-two-datasources] * xref:how-to:data-access.adoc#howto.data-access.configure-two-datasources[#howto.data-access.configure-two-datasources] +* xref:how-to:data-access.adoc#howto.data-access.customize-spring-data-web-support[#howto-use-customize-spring-datas-web-support] * xref:how-to:data-access.adoc#howto.data-access.customize-spring-data-web-support[#howto.data-access.customize-spring-data-web-support] +* xref:how-to:data-access.adoc#howto.data-access.dependency-injection-in-hibernate-components[#howto-use-dependency-injection-hibernate-components] * xref:how-to:data-access.adoc#howto.data-access.dependency-injection-in-hibernate-components[#howto.data-access.dependency-injection-in-hibernate-components] +* xref:how-to:data-access.adoc#howto.data-access.exposing-spring-data-repositories-as-rest[#howto-use-exposing-spring-data-repositories-rest-endpoint] * xref:how-to:data-access.adoc#howto.data-access.exposing-spring-data-repositories-as-rest[#howto.data-access.exposing-spring-data-repositories-as-rest] +* xref:how-to:data-access.adoc#howto.data-access.jpa-properties[#howto-configure-jpa-properties] * xref:how-to:data-access.adoc#howto.data-access.jpa-properties[#howto.data-access.jpa-properties] +* xref:how-to:data-access.adoc#howto.data-access.separate-entity-definitions-from-spring-configuration[#howto-separate-entity-definitions-from-spring-configuration] * xref:how-to:data-access.adoc#howto.data-access.separate-entity-definitions-from-spring-configuration[#howto.data-access.separate-entity-definitions-from-spring-configuration] +* xref:how-to:data-access.adoc#howto.data-access.spring-data-repositories[#howto-use-spring-data-repositories] * xref:how-to:data-access.adoc#howto.data-access.spring-data-repositories[#howto.data-access.spring-data-repositories] +* xref:how-to:data-access.adoc#howto.data-access.use-custom-entity-manager[#howto-use-custom-entity-manager] * xref:how-to:data-access.adoc#howto.data-access.use-custom-entity-manager[#howto.data-access.use-custom-entity-manager] +* xref:how-to:data-access.adoc#howto.data-access.use-multiple-entity-managers[#howto-use-two-entity-managers] * xref:how-to:data-access.adoc#howto.data-access.use-multiple-entity-managers[#howto.data-access.use-multiple-entity-managers] +* xref:how-to:data-access.adoc#howto.data-access.use-spring-data-jpa-and-mongo-repositories[#howto-use-spring-data-jpa--and-mongo-repositories] * xref:how-to:data-access.adoc#howto.data-access.use-spring-data-jpa-and-mongo-repositories[#howto.data-access.use-spring-data-jpa-and-mongo-repositories] +* xref:how-to:data-access.adoc#howto.data-access.use-traditional-persistence-xml[#howto-use-traditional-persistence-xml] * xref:how-to:data-access.adoc#howto.data-access.use-traditional-persistence-xml[#howto.data-access.use-traditional-persistence-xml] -* xref:how-to:data-initialization.adoc#howto.data-initialization[#howto.data-initialization] +* xref:how-to:data-access.adoc#howto.data-access[#howto-data-access] +* xref:how-to:data-access.adoc#howto.data-access[#howto.data-access] +* xref:how-to:data-initialization.adoc#howto.data-initialization.batch[#howto-initialize-a-spring-batch-database] * xref:how-to:data-initialization.adoc#howto.data-initialization.batch[#howto.data-initialization.batch] -* xref:how-to:data-initialization.adoc#howto.data-initialization.dependencies[#howto.data-initialization.dependencies] +* xref:how-to:data-initialization.adoc#howto.data-initialization.dependencies.depends-on-initialization-detection[#howto-initialize-a-database-configuring-dependencies-depends-on-initialization-detection] * xref:how-to:data-initialization.adoc#howto.data-initialization.dependencies.depends-on-initialization-detection[#howto.data-initialization.dependencies.depends-on-initialization-detection] +* xref:how-to:data-initialization.adoc#howto.data-initialization.dependencies.initializer-detection[#howto-initialize-a-database-configuring-dependencies-initializer-detection] * xref:how-to:data-initialization.adoc#howto.data-initialization.dependencies.initializer-detection[#howto.data-initialization.dependencies.initializer-detection] -* xref:how-to:data-initialization.adoc#howto.data-initialization.migration-tool[#howto.data-initialization.migration-tool] -* xref:how-to:data-initialization.adoc#howto.data-initialization.migration-tool.flyway[#howto.data-initialization.migration-tool.flyway] +* xref:how-to:data-initialization.adoc#howto.data-initialization.dependencies[#howto-initialize-a-database-configuring-dependencies] +* xref:how-to:data-initialization.adoc#howto.data-initialization.dependencies[#howto.data-initialization.dependencies] * xref:how-to:data-initialization.adoc#howto.data-initialization.migration-tool.flyway-tests[#howto.data-initialization.migration-tool.flyway-tests] -* xref:how-to:data-initialization.adoc#howto.data-initialization.migration-tool.liquibase[#howto.data-initialization.migration-tool.liquibase] +* xref:how-to:data-initialization.adoc#howto.data-initialization.migration-tool.flyway[#howto-execute-flyway-database-migrations-on-startup] +* xref:how-to:data-initialization.adoc#howto.data-initialization.migration-tool.flyway[#howto.data-initialization.migration-tool.flyway] * xref:how-to:data-initialization.adoc#howto.data-initialization.migration-tool.liquibase-tests[#howto.data-initialization.migration-tool.liquibase-tests] +* xref:how-to:data-initialization.adoc#howto.data-initialization.migration-tool.liquibase[#howto-execute-liquibase-database-migrations-on-startup] +* xref:how-to:data-initialization.adoc#howto.data-initialization.migration-tool.liquibase[#howto.data-initialization.migration-tool.liquibase] +* xref:how-to:data-initialization.adoc#howto.data-initialization.migration-tool[#howto-use-a-higher-level-database-migration-tool] +* xref:how-to:data-initialization.adoc#howto.data-initialization.migration-tool[#howto.data-initialization.migration-tool] +* xref:how-to:data-initialization.adoc#howto.data-initialization.using-basic-sql-scripts[#howto-initialize-a-database-using-basic-scripts] * xref:how-to:data-initialization.adoc#howto.data-initialization.using-basic-sql-scripts[#howto.data-initialization.using-basic-sql-scripts] * xref:how-to:data-initialization.adoc#howto.data-initialization.using-hibernate[#howto.data-initialization.using-hibernate] * xref:how-to:data-initialization.adoc#howto.data-initialization.using-hibernate[#howto.data-initialization.using-jpa] -* xref:how-to:docker-compose.adoc#howto.docker-compose[#howto.docker-compose] +* xref:how-to:data-initialization.adoc#howto.data-initialization[#howto-database-initialization] +* xref:how-to:data-initialization.adoc#howto.data-initialization[#howto.data-initialization] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws.beanstalk.java-se-platform[#cloud-deployment-aws-java-se-platform] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws.beanstalk.java-se-platform[#deployment.cloud.aws.beanstalk.java-se-platform] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws.beanstalk.tomcat-platform[#cloud-deployment-aws-tomcat-platform] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws.beanstalk.tomcat-platform[#deployment.cloud.aws.beanstalk.tomcat-platform] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws.beanstalk[#cloud-deployment-aws-beanstalk] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws.beanstalk[#deployment.cloud.aws.beanstalk] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws.summary[#cloud-deployment-aws-summary] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws.summary[#deployment.cloud.aws.summary] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws[#cloud-deployment-aws] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws[#deployment.cloud.aws] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.azure[#deployment.cloud.azure] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.boxfuse[#cloud-deployment-boxfuse] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.boxfuse[#deployment.cloud.boxfuse] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.cloud-foundry.binding-to-services[#cloud-deployment-cloud-foundry-services] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.cloud-foundry.binding-to-services[#deployment.cloud.cloud-foundry.binding-to-services] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.cloud-foundry[#cloud-deployment-cloud-foundry] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.cloud-foundry[#deployment.cloud.cloud-foundry] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.google[#cloud-deployment-gae] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.google[#deployment.cloud.google] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.heroku[#cloud-deployment-heroku] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.heroku[#deployment.cloud.heroku] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.kubernetes.container-lifecycle[#cloud-deployment-kubernetes-container-lifecycle] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.kubernetes.container-lifecycle[#deployment.cloud.kubernetes.container-lifecycle] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.kubernetes[#cloud-deployment-kubernetes] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.kubernetes[#deployment.cloud.kubernetes] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.openshift[#cloud-deployment-openshift] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.openshift[#deployment.cloud.openshift] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud[#cloud-deployment] +* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud[#deployment.cloud] +* xref:how-to:deployment/index.adoc#howto.deployment[#deployment] +* xref:how-to:deployment/index.adoc[#deployment] +* xref:how-to:deployment/index.adoc[deployment] +* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d.script-customization.when-running.conf-file[#deployment.installing.init-d.script-customization.when-running.conf-file] +* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d.script-customization.when-running.conf-file[#deployment.installing.nix-services.script-customization.when-running.conf-file] +* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d.script-customization.when-running[#deployment-script-customization-when-it-runs] +* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d.script-customization.when-running[#deployment.installing.init-d.script-customization.when-running] +* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d.script-customization.when-running[#deployment.installing.nix-services.script-customization.when-running] +* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d.script-customization.when-written[#deployment-script-customization-when-it-written] +* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d.script-customization.when-written[#deployment.installing.init-d.script-customization.when-written] +* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d.script-customization.when-written[#deployment.installing.nix-services.script-customization.when-written] +* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d.script-customization[#deployment-script-customization] +* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d.script-customization[#deployment.installing.init-d.script-customization] +* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d.script-customization[#deployment.installing.nix-services.script-customization] +* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d.securing[#deployment-initd-service-securing] +* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d.securing[#deployment.installing.init-d.securing] +* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d.securing[#deployment.installing.nix-services.init-d.securing] +* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d[#deployment-initd-service] +* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d[#deployment.installing.init-d] +* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d[#deployment.installing.nix-services.init-d] +* xref:how-to:deployment/installing.adoc#howto.deployment.installing.system-d[#deployment-systemd-service] +* xref:how-to:deployment/installing.adoc#howto.deployment.installing.system-d[#deployment.installing.nix-services.system-d] +* xref:how-to:deployment/installing.adoc#howto.deployment.installing.system-d[#deployment.installing.system-d] +* xref:how-to:deployment/installing.adoc#howto.deployment.installing.windows-services[#deployment-windows] +* xref:how-to:deployment/installing.adoc#howto.deployment.installing.windows-services[#deployment.installing.windows-services] +* xref:how-to:deployment/installing.adoc#howto.deployment.installing[#deployment-install-supported-operating-systems] +* xref:how-to:deployment/installing.adoc#howto.deployment.installing[#deployment-service] +* xref:how-to:deployment/installing.adoc#howto.deployment.installing[#deployment.installing.supported-operating-systems] +* xref:how-to:deployment/installing.adoc#howto.deployment.installing[#deployment.installing] +* xref:how-to:deployment/traditional-deployment.adoc#howto.traditional-deployment.convert-existing-application[#howto-convert-an-existing-application-to-spring-boot] +* xref:how-to:deployment/traditional-deployment.adoc#howto.traditional-deployment.convert-existing-application[#howto.traditional-deployment.convert-existing-application] +* xref:how-to:deployment/traditional-deployment.adoc#howto.traditional-deployment.war[#howto-create-a-deployable-war-file] +* xref:how-to:deployment/traditional-deployment.adoc#howto.traditional-deployment.war[#howto.traditional-deployment.war] +* xref:how-to:deployment/traditional-deployment.adoc#howto.traditional-deployment.weblogic[#howto-weblogic] +* xref:how-to:deployment/traditional-deployment.adoc#howto.traditional-deployment.weblogic[#howto.traditional-deployment.weblogic] +* xref:how-to:deployment/traditional-deployment.adoc#howto.traditional-deployment[#howto-traditional-deployment] +* xref:how-to:deployment/traditional-deployment.adoc#howto.traditional-deployment[#howto.traditional-deployment] * xref:how-to:docker-compose.adoc#howto.docker-compose.jdbc-url[#howto.docker-compose.jdbc-url] * xref:how-to:docker-compose.adoc#howto.docker-compose.sharing-services[#howto.docker-compose.sharing-services] -* xref:how-to:hotswapping.adoc#howto.hotswapping[#howto.hotswapping] +* xref:how-to:docker-compose.adoc#howto.docker-compose[#howto.docker-compose] +* xref:how-to:hotswapping.adoc#howto.hotswapping.fast-application-restarts[#howto-reload-fast-restart] * xref:how-to:hotswapping.adoc#howto.hotswapping.fast-application-restarts[#howto.hotswapping.fast-application-restarts] +* xref:how-to:hotswapping.adoc#howto.hotswapping.reload-java-classes-without-restarting[#howto-reload-java-classes-without-restarting] * xref:how-to:hotswapping.adoc#howto.hotswapping.reload-java-classes-without-restarting[#howto.hotswapping.reload-java-classes-without-restarting] +* xref:how-to:hotswapping.adoc#howto.hotswapping.reload-static-content[#howto-reload-static-content] * xref:how-to:hotswapping.adoc#howto.hotswapping.reload-static-content[#howto.hotswapping.reload-static-content] -* xref:how-to:hotswapping.adoc#howto.hotswapping.reload-templates[#howto.hotswapping.reload-templates] +* xref:how-to:hotswapping.adoc#howto.hotswapping.reload-templates.freemarker[#howto-reload-freemarker-content] * xref:how-to:hotswapping.adoc#howto.hotswapping.reload-templates.freemarker[#howto.hotswapping.reload-templates.freemarker] +* xref:how-to:hotswapping.adoc#howto.hotswapping.reload-templates.groovy[#howto-reload-groovy-template-content] * xref:how-to:hotswapping.adoc#howto.hotswapping.reload-templates.groovy[#howto.hotswapping.reload-templates.groovy] +* xref:how-to:hotswapping.adoc#howto.hotswapping.reload-templates.thymeleaf[#howto-reload-thymeleaf-content] * xref:how-to:hotswapping.adoc#howto.hotswapping.reload-templates.thymeleaf[#howto.hotswapping.reload-templates.thymeleaf] -* xref:how-to:http-clients.adoc#howto.http-clients[#howto.http-clients] +* xref:how-to:hotswapping.adoc#howto.hotswapping.reload-templates[#howto-reload-thymeleaf-template-content] +* xref:how-to:hotswapping.adoc#howto.hotswapping.reload-templates[#howto.hotswapping.reload-templates] +* xref:how-to:hotswapping.adoc#howto.hotswapping[#howto-hotswapping] +* xref:how-to:hotswapping.adoc#howto.hotswapping[#howto.hotswapping] +* xref:how-to:http-clients.adoc#howto.http-clients.rest-template-proxy-configuration[#howto-http-clients-proxy-configuration] * xref:how-to:http-clients.adoc#howto.http-clients.rest-template-proxy-configuration[#howto.http-clients.rest-template-proxy-configuration] +* xref:how-to:http-clients.adoc#howto.http-clients.webclient-reactor-netty-customization[#howto-webclient-reactor-netty-customization] * xref:how-to:http-clients.adoc#howto.http-clients.webclient-reactor-netty-customization[#howto.http-clients.webclient-reactor-netty-customization] +* xref:how-to:http-clients.adoc#howto.http-clients[#howto-http-clients] +* xref:how-to:http-clients.adoc#howto.http-clients[#howto.http-clients] * xref:how-to:index.adoc#howto[#howto] -* xref:how-to:jersey.adoc#howto.jersey[#howto.jersey] +* xref:how-to:index.adoc[#howto] +* xref:how-to:index.adoc[howto] +* xref:how-to:jersey.adoc#howto.jersey.alongside-another-web-framework[#howto-jersey-alongside-another-web-framework] * xref:how-to:jersey.adoc#howto.jersey.alongside-another-web-framework[#howto.jersey.alongside-another-web-framework] +* xref:how-to:jersey.adoc#howto.jersey.spring-security[#howto-jersey-spring-security] * xref:how-to:jersey.adoc#howto.jersey.spring-security[#howto.jersey.spring-security] -* xref:how-to:logging.adoc#howto.logging[#howto.logging] -* xref:how-to:logging.adoc#howto.logging.log4j[#howto.logging.log4j] +* xref:how-to:jersey.adoc#howto.jersey[#howto-jersey] +* xref:how-to:jersey.adoc#howto.jersey[#howto.jersey] * xref:how-to:logging.adoc#howto.logging.log4j.composite-configuration[#howto.logging.log4j.composite-configuration] +* xref:how-to:logging.adoc#howto.logging.log4j.yaml-or-json-config[#howto-configure-log4j-for-logging-yaml-or-json-config] * xref:how-to:logging.adoc#howto.logging.log4j.yaml-or-json-config[#howto.logging.log4j.yaml-or-json-config] -* xref:how-to:logging.adoc#howto.logging.logback[#howto.logging.logback] +* xref:how-to:logging.adoc#howto.logging.log4j[#howto-configure-log4j-for-logging] +* xref:how-to:logging.adoc#howto.logging.log4j[#howto.logging.log4j] +* xref:how-to:logging.adoc#howto.logging.logback.file-only-output[#howto-configure-logback-for-logging-fileonly] * xref:how-to:logging.adoc#howto.logging.logback.file-only-output[#howto.logging.logback.file-only-output] -* xref:how-to:messaging.adoc#howto.messaging[#howto.messaging] -* xref:how-to:messaging.adoc#howto.messaging.disable-transacted-jms-session[#howto.messaging.disable-transacted-jms-session] -* xref:how-to:nosql.adoc#howto.nosql[#howto.nosql] +* xref:how-to:logging.adoc#howto.logging.logback[#howto-configure-logback-for-logging] +* xref:how-to:logging.adoc#howto.logging.logback[#howto.logging.logback] +* xref:how-to:logging.adoc#howto.logging[#howto-logging] +* xref:how-to:logging.adoc#howto.logging[#howto.logging] +* xref:how-to:messaging.adoc#howto.messaging.disable-transacted-jms-session[#howto-jms-disable-transaction] +* xref:how-to:messaging.adoc#howto.messaging.disable-transacted-jms-session[#howto.messaging.disable-transacted-jms-session] +* xref:how-to:messaging.adoc#howto.messaging[#howto-messaging] +* xref:how-to:messaging.adoc#howto.messaging[#howto.messaging] +* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.buildpacks.gradle[#native-image.developing-your-first-application.buildpacks.gradle] +* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.buildpacks.maven[#native-image.developing-your-first-application.buildpacks.maven] +* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.buildpacks.running[#native-image.developing-your-first-application.buildpacks.running] +* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.buildpacks.system-requirements[#native-image.developing-your-first-application.buildpacks.system-requirements] +* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.buildpacks[#native-image.developing-your-first-application.buildpacks] +* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.native-build-tools.gradle[#native-image.developing-your-first-application.native-build-tools.gradle] +* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.native-build-tools.maven[#native-image.developing-your-first-application.native-build-tools.maven] +* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.native-build-tools.prerequisites.linux-macos[#native-image.developing-your-first-application.native-build-tools.prerequisites.linux-macos] +* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.native-build-tools.prerequisites.windows[#native-image.developing-your-first-application.native-build-tools.prerequisites.windows] +* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.native-build-tools.prerequisites[#native-image.developing-your-first-application.native-build-tools.prerequisites] +* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.native-build-tools.running[#native-image.developing-your-first-application.native-build-tools.running] +* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.native-build-tools[#native-image.developing-your-first-application.native-build-tools] +* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.sample-application[#native-image.developing-your-first-application.sample-application] +* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application[#native-image.developing-your-first-application] +* xref:how-to:native-image/testing-native-applications.adoc#howto.native-image.testing.with-native-build-tools.gradle[#native-image.testing.with-native-build-tools.gradle] +* xref:how-to:native-image/testing-native-applications.adoc#howto.native-image.testing.with-native-build-tools.maven[#native-image.testing.with-native-build-tools.maven] +* xref:how-to:native-image/testing-native-applications.adoc#howto.native-image.testing.with-native-build-tools[#native-image.testing.with-native-build-tools] +* xref:how-to:native-image/testing-native-applications.adoc#howto.native-image.testing.with-the-jvm[#native-image.testing.with-the-jvm] +* xref:how-to:native-image/testing-native-applications.adoc#howto.native-image.testing[#native-image.testing] +* xref:how-to:nosql.adoc#howto.nosql.jedis-instead-of-lettuce[#howto-use-jedis-instead-of-lettuce] * xref:how-to:nosql.adoc#howto.nosql.jedis-instead-of-lettuce[#howto.nosql.jedis-instead-of-lettuce] -* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration[#howto.properties-and-configuration] +* xref:how-to:nosql.adoc#howto.nosql[#howto.nosql] +* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.change-configuration-depending-on-the-environment[#howto-change-configuration-depending-on-the-environment] * xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.change-configuration-depending-on-the-environment[#howto.properties-and-configuration.change-configuration-depending-on-the-environment] +* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.discover-build-in-options-for-external-properties[#howto-discover-build-in-options-for-external-properties] * xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.discover-build-in-options-for-external-properties[#howto.properties-and-configuration.discover-build-in-options-for-external-properties] -* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.expand-properties[#howto.properties-and-configuration.expand-properties] +* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.expand-properties.gradle[#howto-automatic-expansion-gradle] * xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.expand-properties.gradle[#howto.properties-and-configuration.expand-properties.gradle] +* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.expand-properties.maven[#howto-automatic-expansion-maven] * xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.expand-properties.maven[#howto.properties-and-configuration.expand-properties.maven] +* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.expand-properties[#howto-automatic-expansion] +* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.expand-properties[#howto.properties-and-configuration.expand-properties] +* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.external-properties-location[#howto-change-the-location-of-external-properties] * xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.external-properties-location[#howto.properties-and-configuration.external-properties-location] +* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.externalize-configuration[#howto-externalize-configuration] * xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.externalize-configuration[#howto.properties-and-configuration.externalize-configuration] +* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.set-active-spring-profiles[#howto-set-active-spring-profiles] * xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.set-active-spring-profiles[#howto.properties-and-configuration.set-active-spring-profiles] * xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.set-default-spring-profile-name[#howto.properties-and-configuration.set-default-spring-profile-name] +* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.short-command-line-arguments[#howto-use-short-command-line-arguments] * xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.short-command-line-arguments[#howto.properties-and-configuration.short-command-line-arguments] +* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.yaml[#howto-use-yaml-for-external-properties] * xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.yaml[#howto.properties-and-configuration.yaml] -* xref:how-to:security.adoc#howto.security[#howto.security] +* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration[#howto-properties-and-configuration] +* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration[#howto.properties-and-configuration] +* xref:how-to:security.adoc#howto.security.change-user-details-service-and-add-user-accounts[#howto-change-the-user-details-service-and-add-user-accounts] * xref:how-to:security.adoc#howto.security.change-user-details-service-and-add-user-accounts[#howto.security.change-user-details-service-and-add-user-accounts] +* xref:how-to:security.adoc#howto.security.enable-https[#howto-enable-https] * xref:how-to:security.adoc#howto.security.enable-https[#howto.security.enable-https] +* xref:how-to:security.adoc#howto.security.switch-off-spring-boot-configuration[#howto-switch-off-spring-boot-security-configuration] * xref:how-to:security.adoc#howto.security.switch-off-spring-boot-configuration[#howto.security.switch-off-spring-boot-configuration] -* xref:how-to:spring-mvc.adoc#howto.spring-mvc[#howto.spring-mvc] +* xref:how-to:security.adoc#howto.security[#howto-security] +* xref:how-to:security.adoc#howto.security[#howto.security] +* xref:how-to:spring-mvc.adoc#howto.spring-mvc.customize-jackson-objectmapper[#howto-customize-the-jackson-objectmapper] * xref:how-to:spring-mvc.adoc#howto.spring-mvc.customize-jackson-objectmapper[#howto.spring-mvc.customize-jackson-objectmapper] +* xref:how-to:spring-mvc.adoc#howto.spring-mvc.customize-responsebody-rendering[#howto-customize-the-responsebody-rendering] * xref:how-to:spring-mvc.adoc#howto.spring-mvc.customize-responsebody-rendering[#howto.spring-mvc.customize-responsebody-rendering] +* xref:how-to:spring-mvc.adoc#howto.spring-mvc.customize-view-resolvers[#howto-customize-view-resolvers] * xref:how-to:spring-mvc.adoc#howto.spring-mvc.customize-view-resolvers[#howto.spring-mvc.customize-view-resolvers] +* xref:how-to:spring-mvc.adoc#howto.spring-mvc.customize-whitelabel-error-page[#howto-customize-the-whitelabel-error-page] * xref:how-to:spring-mvc.adoc#howto.spring-mvc.customize-whitelabel-error-page[#howto.actuator.customize-whitelabel-error-page] +* xref:how-to:spring-mvc.adoc#howto.spring-mvc.multipart-file-uploads[#howto-multipart-file-upload-configuration] * xref:how-to:spring-mvc.adoc#howto.spring-mvc.multipart-file-uploads[#howto.spring-mvc.multipart-file-uploads] +* xref:how-to:spring-mvc.adoc#howto.spring-mvc.switch-off-default-configuration[#howto-switch-off-default-mvc-configuration] * xref:how-to:spring-mvc.adoc#howto.spring-mvc.switch-off-default-configuration[#howto.spring-mvc.switch-off-default-configuration] +* xref:how-to:spring-mvc.adoc#howto.spring-mvc.switch-off-dispatcherservlet[#howto-switch-off-the-spring-mvc-dispatcherservlet] * xref:how-to:spring-mvc.adoc#howto.spring-mvc.switch-off-dispatcherservlet[#howto.spring-mvc.switch-off-dispatcherservlet] +* xref:how-to:spring-mvc.adoc#howto.spring-mvc.write-json-rest-service[#howto-write-a-json-rest-service] * xref:how-to:spring-mvc.adoc#howto.spring-mvc.write-json-rest-service[#howto.spring-mvc.write-json-rest-service] +* xref:how-to:spring-mvc.adoc#howto.spring-mvc.write-xml-rest-service[#howto-write-an-xml-rest-service] * xref:how-to:spring-mvc.adoc#howto.spring-mvc.write-xml-rest-service[#howto.spring-mvc.write-xml-rest-service] -* xref:how-to:testing.adoc#howto.testing[#howto.testing] +* xref:how-to:spring-mvc.adoc#howto.spring-mvc[#howto-spring-mvc] +* xref:how-to:spring-mvc.adoc#howto.spring-mvc[#howto.spring-mvc] * xref:how-to:testing.adoc#howto.testing.slice-tests[#howto.testing.slice-tests] -* xref:how-to:testing.adoc#howto.testing.with-spring-security[#howto.testing.with-spring-security] * xref:how-to:testing.adoc#howto.testing.with-spring-security[#howto-use-test-with-spring-security] -* xref:how-to:deployment/traditional-deployment.adoc#howto.traditional-deployment[#howto.traditional-deployment] -* xref:how-to:deployment/traditional-deployment.adoc#howto.traditional-deployment.convert-existing-application[#howto.traditional-deployment.convert-existing-application] -* xref:how-to:deployment/traditional-deployment.adoc#howto.traditional-deployment.war[#howto.traditional-deployment.war] -* xref:how-to:deployment/traditional-deployment.adoc#howto.traditional-deployment.weblogic[#howto.traditional-deployment.weblogic] +* xref:how-to:testing.adoc#howto.testing.with-spring-security[#howto.spring-mvc.testing.with-spring-security] +* xref:how-to:testing.adoc#howto.testing.with-spring-security[#howto.testing.with-spring-security] +* xref:how-to:testing.adoc#howto.testing[#howto.testing] * xref:how-to:webserver.adoc#howto-configure-webserver-customizers[#howto-configure-webserver-customizers] -* xref:how-to:webserver.adoc#howto.webserver[#howto.webserver] -* xref:how-to:webserver.adoc#howto.webserver.add-servlet-filter-listener[#howto.webserver.add-servlet-filter-listener] -* xref:how-to:webserver.adoc#howto.webserver.add-servlet-filter-listener.spring-bean[#howto.webserver.add-servlet-filter-listener.spring-bean] +* xref:how-to:webserver.adoc#howto.webserver.add-servlet-filter-listener.spring-bean.disable[#howto-disable-registration-of-a-servlet-or-filter] * xref:how-to:webserver.adoc#howto.webserver.add-servlet-filter-listener.spring-bean.disable[#howto.webserver.add-servlet-filter-listener.spring-bean.disable] +* xref:how-to:webserver.adoc#howto.webserver.add-servlet-filter-listener.spring-bean[#howto-add-a-servlet-filter-or-listener-as-spring-bean] +* xref:how-to:webserver.adoc#howto.webserver.add-servlet-filter-listener.spring-bean[#howto.webserver.add-servlet-filter-listener.spring-bean] +* xref:how-to:webserver.adoc#howto.webserver.add-servlet-filter-listener.using-scanning[#howto-add-a-servlet-filter-or-listener-using-scanning] * xref:how-to:webserver.adoc#howto.webserver.add-servlet-filter-listener.using-scanning[#howto.webserver.add-servlet-filter-listener.using-scanning] +* xref:how-to:webserver.adoc#howto.webserver.add-servlet-filter-listener[#howto-add-a-servlet-filter-or-listener] +* xref:how-to:webserver.adoc#howto.webserver.add-servlet-filter-listener[#howto.webserver.add-servlet-filter-listener] +* xref:how-to:webserver.adoc#howto.webserver.change-port[#howto-change-the-http-port] * xref:how-to:webserver.adoc#howto.webserver.change-port[#howto.webserver.change-port] -* xref:how-to:webserver.adoc#howto.webserver.configure[#howto.webserver.configure] +* xref:how-to:webserver.adoc#howto.webserver.configure-access-logs[#howto-configure-accesslogs] * xref:how-to:webserver.adoc#howto.webserver.configure-access-logs[#howto.webserver.configure-access-logs] -* xref:how-to:webserver.adoc#howto.webserver.configure-http2[#howto.webserver.configure-http2] +* xref:how-to:webserver.adoc#howto.webserver.configure-http2.jetty[#howto-configure-http2-jetty] * xref:how-to:webserver.adoc#howto.webserver.configure-http2.jetty[#howto.webserver.configure-http2.jetty] +* xref:how-to:webserver.adoc#howto.webserver.configure-http2.netty[#howto-configure-http2-netty] * xref:how-to:webserver.adoc#howto.webserver.configure-http2.netty[#howto.webserver.configure-http2.netty] +* xref:how-to:webserver.adoc#howto.webserver.configure-http2.tomcat[#howto-configure-http2-tomcat] * xref:how-to:webserver.adoc#howto.webserver.configure-http2.tomcat[#howto.webserver.configure-http2.tomcat] +* xref:how-to:webserver.adoc#howto.webserver.configure-http2.undertow[#howto-configure-http2-undertow] * xref:how-to:webserver.adoc#howto.webserver.configure-http2.undertow[#howto.webserver.configure-http2.undertow] -* xref:how-to:webserver.adoc#howto.webserver.configure-ssl[#howto.webserver.configure-ssl] +* xref:how-to:webserver.adoc#howto.webserver.configure-http2[#howto-configure-http2] +* xref:how-to:webserver.adoc#howto.webserver.configure-http2[#howto.webserver.configure-http2] * xref:how-to:webserver.adoc#howto.webserver.configure-ssl.pem-files[#howto.webserver.configure-ssl.pem-files] +* xref:how-to:webserver.adoc#howto.webserver.configure-ssl[#howto-configure-ssl] +* xref:how-to:webserver.adoc#howto.webserver.configure-ssl[#howto.webserver.configure-ssl] +* xref:how-to:webserver.adoc#howto.webserver.configure[#howto-configure-webserver] +* xref:how-to:webserver.adoc#howto.webserver.configure[#howto.webserver.configure] +* xref:how-to:webserver.adoc#howto.webserver.create-websocket-endpoints-using-serverendpoint[#howto-create-websocket-endpoints-using-serverendpoint] * xref:how-to:webserver.adoc#howto.webserver.create-websocket-endpoints-using-serverendpoint[#howto.webserver.create-websocket-endpoints-using-serverendpoint] +* xref:how-to:webserver.adoc#howto.webserver.disable[#howto-disable-web-server] * xref:how-to:webserver.adoc#howto.webserver.disable[#howto.webserver.disable] +* xref:how-to:webserver.adoc#howto.webserver.discover-port[#howto-discover-the-http-port-at-runtime] * xref:how-to:webserver.adoc#howto.webserver.discover-port[#howto.webserver.discover-port] +* xref:how-to:webserver.adoc#howto.webserver.enable-multiple-connectors-in-tomcat[#howto-enable-multiple-connectors-in-tomcat] * xref:how-to:webserver.adoc#howto.webserver.enable-multiple-connectors-in-tomcat[#howto.webserver.enable-multiple-connectors-in-tomcat] +* xref:how-to:webserver.adoc#howto.webserver.enable-multiple-listeners-in-undertow[#howto-enable-multiple-listeners-in-undertow] * xref:how-to:webserver.adoc#howto.webserver.enable-multiple-listeners-in-undertow[#howto.webserver.enable-multiple-listeners-in-undertow] +* xref:how-to:webserver.adoc#howto.webserver.enable-response-compression[#how-to-enable-http-response-compression] * xref:how-to:webserver.adoc#howto.webserver.enable-response-compression[#howto.webserver.enable-response-compression] +* xref:how-to:webserver.adoc#howto.webserver.enable-tomcat-mbean-registry[#howto-enable-tomcat-mbean-registry] * xref:how-to:webserver.adoc#howto.webserver.enable-tomcat-mbean-registry[#howto.webserver.enable-tomcat-mbean-registry] +* xref:how-to:webserver.adoc#howto.webserver.use-another[#howto-use-another-web-server] * xref:how-to:webserver.adoc#howto.webserver.use-another[#howto.webserver.use-another] -* xref:how-to:webserver.adoc#howto.webserver.use-behind-a-proxy-server[#howto.webserver.use-behind-a-proxy-server] +* xref:how-to:webserver.adoc#howto.webserver.use-behind-a-proxy-server.tomcat[#howto-customize-tomcat-behind-a-proxy-server] * xref:how-to:webserver.adoc#howto.webserver.use-behind-a-proxy-server.tomcat[#howto.webserver.use-behind-a-proxy-server.tomcat] +* xref:how-to:webserver.adoc#howto.webserver.use-behind-a-proxy-server[#howto-use-behind-a-proxy-server] +* xref:how-to:webserver.adoc#howto.webserver.use-behind-a-proxy-server[#howto.webserver.use-behind-a-proxy-server] +* xref:how-to:webserver.adoc#howto.webserver.use-random-port[#howto-user-a-random-unassigned-http-port] * xref:how-to:webserver.adoc#howto.webserver.use-random-port[#howto.webserver.use-random-port] -* xref:maven-plugin:aot.adoc#aot[maven-plugin#aot] -* xref:maven-plugin:aot.adoc#aot.process-aot-goal[maven-plugin#aot.process-aot-goal] +* xref:how-to:webserver.adoc#howto.webserver[#howto-embedded-web-servers] +* xref:how-to:webserver.adoc#howto.webserver[#howto.webserver] +* xref:index.adoc[#getting-started.introducing-spring-boot] +* xref:index.adoc[#getting-started] +* xref:index.adoc[#index] +* xref:index.adoc[#spring-boot-reference-documentation] +* xref:index.adoc[getting-started] * xref:maven-plugin:aot.adoc#aot.process-aot-goal.optional-parameters[maven-plugin#aot.process-aot-goal.optional-parameters] -* xref:maven-plugin:aot.adoc#aot.process-aot-goal.parameter-details[maven-plugin#aot.process-aot-goal.parameter-details] * xref:maven-plugin:aot.adoc#aot.process-aot-goal.parameter-details.arguments[maven-plugin#aot.process-aot-goal.parameter-details.arguments] * xref:maven-plugin:aot.adoc#aot.process-aot-goal.parameter-details.classes-directory[maven-plugin#aot.process-aot-goal.parameter-details.classes-directory] * xref:maven-plugin:aot.adoc#aot.process-aot-goal.parameter-details.compiler-arguments[maven-plugin#aot.process-aot-goal.parameter-details.compiler-arguments] @@ -495,10 +737,10 @@ * xref:maven-plugin:aot.adoc#aot.process-aot-goal.parameter-details.profiles[maven-plugin#aot.process-aot-goal.parameter-details.profiles] * xref:maven-plugin:aot.adoc#aot.process-aot-goal.parameter-details.skip[maven-plugin#aot.process-aot-goal.parameter-details.skip] * xref:maven-plugin:aot.adoc#aot.process-aot-goal.parameter-details.system-property-variables[maven-plugin#aot.process-aot-goal.parameter-details.system-property-variables] +* xref:maven-plugin:aot.adoc#aot.process-aot-goal.parameter-details[maven-plugin#aot.process-aot-goal.parameter-details] * xref:maven-plugin:aot.adoc#aot.process-aot-goal.required-parameters[maven-plugin#aot.process-aot-goal.required-parameters] -* xref:maven-plugin:aot.adoc#aot.process-test-aot-goal[maven-plugin#aot.process-test-aot-goal] +* xref:maven-plugin:aot.adoc#aot.process-aot-goal[maven-plugin#aot.process-aot-goal] * xref:maven-plugin:aot.adoc#aot.process-test-aot-goal.optional-parameters[maven-plugin#aot.process-test-aot-goal.optional-parameters] -* xref:maven-plugin:aot.adoc#aot.process-test-aot-goal.parameter-details[maven-plugin#aot.process-test-aot-goal.parameter-details] * xref:maven-plugin:aot.adoc#aot.process-test-aot-goal.parameter-details.classes-directory[maven-plugin#aot.process-test-aot-goal.parameter-details.classes-directory] * xref:maven-plugin:aot.adoc#aot.process-test-aot-goal.parameter-details.compiler-arguments[maven-plugin#aot.process-test-aot-goal.parameter-details.compiler-arguments] * xref:maven-plugin:aot.adoc#aot.process-test-aot-goal.parameter-details.exclude-group-ids[maven-plugin#aot.process-test-aot-goal.parameter-details.exclude-group-ids] @@ -512,14 +754,14 @@ * xref:maven-plugin:aot.adoc#aot.process-test-aot-goal.parameter-details.skip[maven-plugin#aot.process-test-aot-goal.parameter-details.skip] * xref:maven-plugin:aot.adoc#aot.process-test-aot-goal.parameter-details.system-property-variables[maven-plugin#aot.process-test-aot-goal.parameter-details.system-property-variables] * xref:maven-plugin:aot.adoc#aot.process-test-aot-goal.parameter-details.test-classes-directory[maven-plugin#aot.process-test-aot-goal.parameter-details.test-classes-directory] +* xref:maven-plugin:aot.adoc#aot.process-test-aot-goal.parameter-details[maven-plugin#aot.process-test-aot-goal.parameter-details] * xref:maven-plugin:aot.adoc#aot.process-test-aot-goal.required-parameters[maven-plugin#aot.process-test-aot-goal.required-parameters] -* xref:maven-plugin:aot.adoc#aot.processing-applications[maven-plugin#aot.processing-applications] +* xref:maven-plugin:aot.adoc#aot.process-test-aot-goal[maven-plugin#aot.process-test-aot-goal] * xref:maven-plugin:aot.adoc#aot.processing-applications.using-the-native-profile[maven-plugin#aot.processing-applications.using-the-native-profile] +* xref:maven-plugin:aot.adoc#aot.processing-applications[maven-plugin#aot.processing-applications] * xref:maven-plugin:aot.adoc#aot.processing-tests[maven-plugin#aot.processing-tests] -* xref:maven-plugin:build-image.adoc#build-image[maven-plugin#build-image] -* xref:maven-plugin:build-image.adoc#build-image.build-image-goal[maven-plugin#build-image.build-image-goal] +* xref:maven-plugin:aot.adoc#aot[maven-plugin#aot] * xref:maven-plugin:build-image.adoc#build-image.build-image-goal.optional-parameters[maven-plugin#build-image.build-image-goal.optional-parameters] -* xref:maven-plugin:build-image.adoc#build-image.build-image-goal.parameter-details[maven-plugin#build-image.build-image-goal.parameter-details] * xref:maven-plugin:build-image.adoc#build-image.build-image-goal.parameter-details.classifier[maven-plugin#build-image.build-image-goal.parameter-details.classifier] * xref:maven-plugin:build-image.adoc#build-image.build-image-goal.parameter-details.docker[maven-plugin#build-image.build-image-goal.parameter-details.docker] * xref:maven-plugin:build-image.adoc#build-image.build-image-goal.parameter-details.exclude-devtools[maven-plugin#build-image.build-image-goal.parameter-details.exclude-devtools] @@ -531,16 +773,16 @@ * xref:maven-plugin:build-image.adoc#build-image.build-image-goal.parameter-details.include-tools[maven-plugin#build-image.build-image-goal.parameter-details.include-tools] * xref:maven-plugin:build-image.adoc#build-image.build-image-goal.parameter-details.includes[maven-plugin#build-image.build-image-goal.parameter-details.includes] * xref:maven-plugin:build-image.adoc#build-image.build-image-goal.parameter-details.layers[maven-plugin#build-image.build-image-goal.parameter-details.layers] -* xref:maven-plugin:build-image.adoc#build-image.build-image-goal.parameter-details.layout[maven-plugin#build-image.build-image-goal.parameter-details.layout] * xref:maven-plugin:build-image.adoc#build-image.build-image-goal.parameter-details.layout-factory[maven-plugin#build-image.build-image-goal.parameter-details.layout-factory] +* xref:maven-plugin:build-image.adoc#build-image.build-image-goal.parameter-details.layout[maven-plugin#build-image.build-image-goal.parameter-details.layout] * xref:maven-plugin:build-image.adoc#build-image.build-image-goal.parameter-details.loader-implementation[maven-plugin#build-image.build-image-goal.parameter-details.loader-implementation] * xref:maven-plugin:build-image.adoc#build-image.build-image-goal.parameter-details.main-class[maven-plugin#build-image.build-image-goal.parameter-details.main-class] * xref:maven-plugin:build-image.adoc#build-image.build-image-goal.parameter-details.skip[maven-plugin#build-image.build-image-goal.parameter-details.skip] * xref:maven-plugin:build-image.adoc#build-image.build-image-goal.parameter-details.source-directory[maven-plugin#build-image.build-image-goal.parameter-details.source-directory] +* xref:maven-plugin:build-image.adoc#build-image.build-image-goal.parameter-details[maven-plugin#build-image.build-image-goal.parameter-details] * xref:maven-plugin:build-image.adoc#build-image.build-image-goal.required-parameters[maven-plugin#build-image.build-image-goal.required-parameters] -* xref:maven-plugin:build-image.adoc#build-image.build-image-no-fork-goal[maven-plugin#build-image.build-image-no-fork-goal] +* xref:maven-plugin:build-image.adoc#build-image.build-image-goal[maven-plugin#build-image.build-image-goal] * xref:maven-plugin:build-image.adoc#build-image.build-image-no-fork-goal.optional-parameters[maven-plugin#build-image.build-image-no-fork-goal.optional-parameters] -* xref:maven-plugin:build-image.adoc#build-image.build-image-no-fork-goal.parameter-details[maven-plugin#build-image.build-image-no-fork-goal.parameter-details] * xref:maven-plugin:build-image.adoc#build-image.build-image-no-fork-goal.parameter-details.classifier[maven-plugin#build-image.build-image-no-fork-goal.parameter-details.classifier] * xref:maven-plugin:build-image.adoc#build-image.build-image-no-fork-goal.parameter-details.docker[maven-plugin#build-image.build-image-no-fork-goal.parameter-details.docker] * xref:maven-plugin:build-image.adoc#build-image.build-image-no-fork-goal.parameter-details.exclude-devtools[maven-plugin#build-image.build-image-no-fork-goal.parameter-details.exclude-devtools] @@ -552,59 +794,59 @@ * xref:maven-plugin:build-image.adoc#build-image.build-image-no-fork-goal.parameter-details.include-tools[maven-plugin#build-image.build-image-no-fork-goal.parameter-details.include-tools] * xref:maven-plugin:build-image.adoc#build-image.build-image-no-fork-goal.parameter-details.includes[maven-plugin#build-image.build-image-no-fork-goal.parameter-details.includes] * xref:maven-plugin:build-image.adoc#build-image.build-image-no-fork-goal.parameter-details.layers[maven-plugin#build-image.build-image-no-fork-goal.parameter-details.layers] -* xref:maven-plugin:build-image.adoc#build-image.build-image-no-fork-goal.parameter-details.layout[maven-plugin#build-image.build-image-no-fork-goal.parameter-details.layout] * xref:maven-plugin:build-image.adoc#build-image.build-image-no-fork-goal.parameter-details.layout-factory[maven-plugin#build-image.build-image-no-fork-goal.parameter-details.layout-factory] +* xref:maven-plugin:build-image.adoc#build-image.build-image-no-fork-goal.parameter-details.layout[maven-plugin#build-image.build-image-no-fork-goal.parameter-details.layout] * xref:maven-plugin:build-image.adoc#build-image.build-image-no-fork-goal.parameter-details.loader-implementation[maven-plugin#build-image.build-image-no-fork-goal.parameter-details.loader-implementation] * xref:maven-plugin:build-image.adoc#build-image.build-image-no-fork-goal.parameter-details.main-class[maven-plugin#build-image.build-image-no-fork-goal.parameter-details.main-class] * xref:maven-plugin:build-image.adoc#build-image.build-image-no-fork-goal.parameter-details.skip[maven-plugin#build-image.build-image-no-fork-goal.parameter-details.skip] * xref:maven-plugin:build-image.adoc#build-image.build-image-no-fork-goal.parameter-details.source-directory[maven-plugin#build-image.build-image-no-fork-goal.parameter-details.source-directory] +* xref:maven-plugin:build-image.adoc#build-image.build-image-no-fork-goal.parameter-details[maven-plugin#build-image.build-image-no-fork-goal.parameter-details] * xref:maven-plugin:build-image.adoc#build-image.build-image-no-fork-goal.required-parameters[maven-plugin#build-image.build-image-no-fork-goal.required-parameters] -* xref:maven-plugin:build-image.adoc#build-image.customization[maven-plugin#build-image.customization] +* xref:maven-plugin:build-image.adoc#build-image.build-image-no-fork-goal[maven-plugin#build-image.build-image-no-fork-goal] * xref:maven-plugin:build-image.adoc#build-image.customization.tags[maven-plugin#build-image.customization.tags] +* xref:maven-plugin:build-image.adoc#build-image.customization[maven-plugin#build-image.customization] * xref:maven-plugin:build-image.adoc#build-image.docker-daemon[maven-plugin#build-image.docker-daemon] * xref:maven-plugin:build-image.adoc#build-image.docker-registry[maven-plugin#build-image.docker-registry] -* xref:maven-plugin:build-image.adoc#build-image.examples[maven-plugin#build-image.examples] * xref:maven-plugin:build-image.adoc#build-image.examples.builder-configuration[maven-plugin#build-image.examples.builder-configuration] * xref:maven-plugin:build-image.adoc#build-image.examples.buildpacks[maven-plugin#build-image.examples.buildpacks] * xref:maven-plugin:build-image.adoc#build-image.examples.caches[maven-plugin#build-image.examples.caches] * xref:maven-plugin:build-image.adoc#build-image.examples.custom-image-builder[maven-plugin#build-image.examples.custom-image-builder] * xref:maven-plugin:build-image.adoc#build-image.examples.custom-image-name[maven-plugin#build-image.examples.custom-image-name] -* xref:maven-plugin:build-image.adoc#build-image.examples.docker[maven-plugin#build-image.examples.docker] * xref:maven-plugin:build-image.adoc#build-image.examples.docker.auth[maven-plugin#build-image.examples.docker.auth] * xref:maven-plugin:build-image.adoc#build-image.examples.docker.colima[maven-plugin#build-image.examples.docker.colima] * xref:maven-plugin:build-image.adoc#build-image.examples.docker.minikube[maven-plugin#build-image.examples.docker.minikube] * xref:maven-plugin:build-image.adoc#build-image.examples.docker.podman[maven-plugin#build-image.examples.docker.podman] +* xref:maven-plugin:build-image.adoc#build-image.examples.docker[maven-plugin#build-image.examples.docker] * xref:maven-plugin:build-image.adoc#build-image.examples.publish[maven-plugin#build-image.examples.publish] * xref:maven-plugin:build-image.adoc#build-image.examples.runtime-jvm-configuration[maven-plugin#build-image.examples.runtime-jvm-configuration] -* xref:maven-plugin:build-info.adoc#build-info[maven-plugin#build-info] -* xref:maven-plugin:build-info.adoc#build-info.build-info-goal[maven-plugin#build-info.build-info-goal] +* xref:maven-plugin:build-image.adoc#build-image.examples[maven-plugin#build-image.examples] +* xref:maven-plugin:build-image.adoc#build-image[maven-plugin#build-image] * xref:maven-plugin:build-info.adoc#build-info.build-info-goal.optional-parameters[maven-plugin#build-info.build-info-goal.optional-parameters] -* xref:maven-plugin:build-info.adoc#build-info.build-info-goal.parameter-details[maven-plugin#build-info.build-info-goal.parameter-details] * xref:maven-plugin:build-info.adoc#build-info.build-info-goal.parameter-details.additional-properties[maven-plugin#build-info.build-info-goal.parameter-details.additional-properties] * xref:maven-plugin:build-info.adoc#build-info.build-info-goal.parameter-details.exclude-info-properties[maven-plugin#build-info.build-info-goal.parameter-details.exclude-info-properties] * xref:maven-plugin:build-info.adoc#build-info.build-info-goal.parameter-details.output-file[maven-plugin#build-info.build-info-goal.parameter-details.output-file] * xref:maven-plugin:build-info.adoc#build-info.build-info-goal.parameter-details.skip[maven-plugin#build-info.build-info-goal.parameter-details.skip] * xref:maven-plugin:build-info.adoc#build-info.build-info-goal.parameter-details.time[maven-plugin#build-info.build-info-goal.parameter-details.time] +* xref:maven-plugin:build-info.adoc#build-info.build-info-goal.parameter-details[maven-plugin#build-info.build-info-goal.parameter-details] +* xref:maven-plugin:build-info.adoc#build-info.build-info-goal[maven-plugin#build-info.build-info-goal] +* xref:maven-plugin:build-info.adoc#build-info[maven-plugin#build-info] * xref:maven-plugin:getting-started.adoc#getting-started[maven-plugin#getting-started] * xref:maven-plugin:goals.adoc#goals[maven-plugin#goals] -* xref:maven-plugin:help.adoc#help[maven-plugin#help] -* xref:maven-plugin:help.adoc#help.help-goal[maven-plugin#help.help-goal] * xref:maven-plugin:help.adoc#help.help-goal.optional-parameters[maven-plugin#help.help-goal.optional-parameters] -* xref:maven-plugin:help.adoc#help.help-goal.parameter-details[maven-plugin#help.help-goal.parameter-details] * xref:maven-plugin:help.adoc#help.help-goal.parameter-details.detail[maven-plugin#help.help-goal.parameter-details.detail] * xref:maven-plugin:help.adoc#help.help-goal.parameter-details.goal[maven-plugin#help.help-goal.parameter-details.goal] * xref:maven-plugin:help.adoc#help.help-goal.parameter-details.indent-size[maven-plugin#help.help-goal.parameter-details.indent-size] * xref:maven-plugin:help.adoc#help.help-goal.parameter-details.line-length[maven-plugin#help.help-goal.parameter-details.line-length] +* xref:maven-plugin:help.adoc#help.help-goal.parameter-details[maven-plugin#help.help-goal.parameter-details] +* xref:maven-plugin:help.adoc#help.help-goal[maven-plugin#help.help-goal] +* xref:maven-plugin:help.adoc#help[maven-plugin#help] * xref:maven-plugin:index.adoc#maven-plugin[maven-plugin#maven-plugin] -* xref:maven-plugin:integration-tests.adoc#integration-tests[maven-plugin#integration-tests] -* xref:maven-plugin:integration-tests.adoc#integration-tests.examples[maven-plugin#integration-tests.examples] * xref:maven-plugin:integration-tests.adoc#integration-tests.examples.jmx-port[maven-plugin#integration-tests.examples.jmx-port] * xref:maven-plugin:integration-tests.adoc#integration-tests.examples.random-port[maven-plugin#integration-tests.examples.random-port] * xref:maven-plugin:integration-tests.adoc#integration-tests.examples.skip[maven-plugin#integration-tests.examples.skip] +* xref:maven-plugin:integration-tests.adoc#integration-tests.examples[maven-plugin#integration-tests.examples] * xref:maven-plugin:integration-tests.adoc#integration-tests.no-starter-parent[maven-plugin#integration-tests.no-starter-parent] -* xref:maven-plugin:integration-tests.adoc#integration-tests.start-goal[maven-plugin#integration-tests.start-goal] * xref:maven-plugin:integration-tests.adoc#integration-tests.start-goal.optional-parameters[maven-plugin#integration-tests.start-goal.optional-parameters] -* xref:maven-plugin:integration-tests.adoc#integration-tests.start-goal.parameter-details[maven-plugin#integration-tests.start-goal.parameter-details] * xref:maven-plugin:integration-tests.adoc#integration-tests.start-goal.parameter-details.add-resources[maven-plugin#integration-tests.start-goal.parameter-details.add-resources] * xref:maven-plugin:integration-tests.adoc#integration-tests.start-goal.parameter-details.additional-classpath-elements[maven-plugin#integration-tests.start-goal.parameter-details.additional-classpath-elements] * xref:maven-plugin:integration-tests.adoc#integration-tests.start-goal.parameter-details.agents[maven-plugin#integration-tests.start-goal.parameter-details.agents] @@ -628,15 +870,16 @@ * xref:maven-plugin:integration-tests.adoc#integration-tests.start-goal.parameter-details.use-test-classpath[maven-plugin#integration-tests.start-goal.parameter-details.use-test-classpath] * xref:maven-plugin:integration-tests.adoc#integration-tests.start-goal.parameter-details.wait[maven-plugin#integration-tests.start-goal.parameter-details.wait] * xref:maven-plugin:integration-tests.adoc#integration-tests.start-goal.parameter-details.working-directory[maven-plugin#integration-tests.start-goal.parameter-details.working-directory] +* xref:maven-plugin:integration-tests.adoc#integration-tests.start-goal.parameter-details[maven-plugin#integration-tests.start-goal.parameter-details] * xref:maven-plugin:integration-tests.adoc#integration-tests.start-goal.required-parameters[maven-plugin#integration-tests.start-goal.required-parameters] -* xref:maven-plugin:integration-tests.adoc#integration-tests.stop-goal[maven-plugin#integration-tests.stop-goal] +* xref:maven-plugin:integration-tests.adoc#integration-tests.start-goal[maven-plugin#integration-tests.start-goal] * xref:maven-plugin:integration-tests.adoc#integration-tests.stop-goal.optional-parameters[maven-plugin#integration-tests.stop-goal.optional-parameters] -* xref:maven-plugin:integration-tests.adoc#integration-tests.stop-goal.parameter-details[maven-plugin#integration-tests.stop-goal.parameter-details] * xref:maven-plugin:integration-tests.adoc#integration-tests.stop-goal.parameter-details.jmx-name[maven-plugin#integration-tests.stop-goal.parameter-details.jmx-name] * xref:maven-plugin:integration-tests.adoc#integration-tests.stop-goal.parameter-details.jmx-port[maven-plugin#integration-tests.stop-goal.parameter-details.jmx-port] * xref:maven-plugin:integration-tests.adoc#integration-tests.stop-goal.parameter-details.skip[maven-plugin#integration-tests.stop-goal.parameter-details.skip] -* xref:maven-plugin:packaging.adoc#packaging[maven-plugin#packaging] -* xref:maven-plugin:packaging.adoc#packaging.examples[maven-plugin#packaging.examples] +* xref:maven-plugin:integration-tests.adoc#integration-tests.stop-goal.parameter-details[maven-plugin#integration-tests.stop-goal.parameter-details] +* xref:maven-plugin:integration-tests.adoc#integration-tests.stop-goal[maven-plugin#integration-tests.stop-goal] +* xref:maven-plugin:integration-tests.adoc#integration-tests[maven-plugin#integration-tests] * xref:maven-plugin:packaging.adoc#packaging.examples.custom-classifier[maven-plugin#packaging.examples.custom-classifier] * xref:maven-plugin:packaging.adoc#packaging.examples.custom-layers-configuration[maven-plugin#packaging.examples.custom-layers-configuration] * xref:maven-plugin:packaging.adoc#packaging.examples.custom-layout[maven-plugin#packaging.examples.custom-layout] @@ -644,15 +887,14 @@ * xref:maven-plugin:packaging.adoc#packaging.examples.exclude-dependency[maven-plugin#packaging.examples.exclude-dependency] * xref:maven-plugin:packaging.adoc#packaging.examples.layered-archive-tools[maven-plugin#packaging.examples.layered-archive-tools] * xref:maven-plugin:packaging.adoc#packaging.examples.local-artifact[maven-plugin#packaging.examples.local-artifact] -* xref:maven-plugin:packaging.adoc#packaging.layers[maven-plugin#packaging.layers] +* xref:maven-plugin:packaging.adoc#packaging.examples[maven-plugin#packaging.examples] * xref:maven-plugin:packaging.adoc#packaging.layers.configuration[maven-plugin#packaging.layers.configuration] -* xref:maven-plugin:packaging.adoc#packaging.repackage-goal[maven-plugin#packaging.repackage-goal] +* xref:maven-plugin:packaging.adoc#packaging.layers[maven-plugin#packaging.layers] * xref:maven-plugin:packaging.adoc#packaging.repackage-goal.optional-parameters[maven-plugin#packaging.repackage-goal.optional-parameters] -* xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details[maven-plugin#packaging.repackage-goal.parameter-details] * xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details.attach[maven-plugin#packaging.repackage-goal.parameter-details.attach] * xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details.classifier[maven-plugin#packaging.repackage-goal.parameter-details.classifier] -* xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details.embedded-launch-script[maven-plugin#packaging.repackage-goal.parameter-details.embedded-launch-script] * xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details.embedded-launch-script-properties[maven-plugin#packaging.repackage-goal.parameter-details.embedded-launch-script-properties] +* xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details.embedded-launch-script[maven-plugin#packaging.repackage-goal.parameter-details.embedded-launch-script] * xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details.exclude-devtools[maven-plugin#packaging.repackage-goal.parameter-details.exclude-devtools] * xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details.exclude-docker-compose[maven-plugin#packaging.repackage-goal.parameter-details.exclude-docker-compose] * xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details.exclude-group-ids[maven-plugin#packaging.repackage-goal.parameter-details.exclude-group-ids] @@ -662,25 +904,25 @@ * xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details.include-tools[maven-plugin#packaging.repackage-goal.parameter-details.include-tools] * xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details.includes[maven-plugin#packaging.repackage-goal.parameter-details.includes] * xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details.layers[maven-plugin#packaging.repackage-goal.parameter-details.layers] -* xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details.layout[maven-plugin#packaging.repackage-goal.parameter-details.layout] * xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details.layout-factory[maven-plugin#packaging.repackage-goal.parameter-details.layout-factory] +* xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details.layout[maven-plugin#packaging.repackage-goal.parameter-details.layout] * xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details.loader-implementation[maven-plugin#packaging.repackage-goal.parameter-details.loader-implementation] * xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details.main-class[maven-plugin#packaging.repackage-goal.parameter-details.main-class] * xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details.output-directory[maven-plugin#packaging.repackage-goal.parameter-details.output-directory] * xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details.output-timestamp[maven-plugin#packaging.repackage-goal.parameter-details.output-timestamp] * xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details.requires-unpack[maven-plugin#packaging.repackage-goal.parameter-details.requires-unpack] * xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details.skip[maven-plugin#packaging.repackage-goal.parameter-details.skip] +* xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details[maven-plugin#packaging.repackage-goal.parameter-details] * xref:maven-plugin:packaging.adoc#packaging.repackage-goal.required-parameters[maven-plugin#packaging.repackage-goal.required-parameters] -* xref:maven-plugin:run.adoc#run[maven-plugin#run] -* xref:maven-plugin:run.adoc#run.examples[maven-plugin#run.examples] +* xref:maven-plugin:packaging.adoc#packaging.repackage-goal[maven-plugin#packaging.repackage-goal] +* xref:maven-plugin:packaging.adoc#packaging[maven-plugin#packaging] * xref:maven-plugin:run.adoc#run.examples.debug[maven-plugin#run.examples.debug] * xref:maven-plugin:run.adoc#run.examples.environment-variables[maven-plugin#run.examples.environment-variables] * xref:maven-plugin:run.adoc#run.examples.specify-active-profiles[maven-plugin#run.examples.specify-active-profiles] * xref:maven-plugin:run.adoc#run.examples.system-properties[maven-plugin#run.examples.system-properties] * xref:maven-plugin:run.adoc#run.examples.using-application-arguments[maven-plugin#run.examples.using-application-arguments] -* xref:maven-plugin:run.adoc#run.run-goal[maven-plugin#run.run-goal] +* xref:maven-plugin:run.adoc#run.examples[maven-plugin#run.examples] * xref:maven-plugin:run.adoc#run.run-goal.optional-parameters[maven-plugin#run.run-goal.optional-parameters] -* xref:maven-plugin:run.adoc#run.run-goal.parameter-details[maven-plugin#run.run-goal.parameter-details] * xref:maven-plugin:run.adoc#run.run-goal.parameter-details.add-resources[maven-plugin#run.run-goal.parameter-details.add-resources] * xref:maven-plugin:run.adoc#run.run-goal.parameter-details.additional-classpath-elements[maven-plugin#run.run-goal.parameter-details.additional-classpath-elements] * xref:maven-plugin:run.adoc#run.run-goal.parameter-details.agents[maven-plugin#run.run-goal.parameter-details.agents] @@ -701,10 +943,10 @@ * xref:maven-plugin:run.adoc#run.run-goal.parameter-details.system-property-variables[maven-plugin#run.run-goal.parameter-details.system-property-variables] * xref:maven-plugin:run.adoc#run.run-goal.parameter-details.use-test-classpath[maven-plugin#run.run-goal.parameter-details.use-test-classpath] * xref:maven-plugin:run.adoc#run.run-goal.parameter-details.working-directory[maven-plugin#run.run-goal.parameter-details.working-directory] +* xref:maven-plugin:run.adoc#run.run-goal.parameter-details[maven-plugin#run.run-goal.parameter-details] * xref:maven-plugin:run.adoc#run.run-goal.required-parameters[maven-plugin#run.run-goal.required-parameters] -* xref:maven-plugin:run.adoc#run.test-run-goal[maven-plugin#run.test-run-goal] +* xref:maven-plugin:run.adoc#run.run-goal[maven-plugin#run.run-goal] * xref:maven-plugin:run.adoc#run.test-run-goal.optional-parameters[maven-plugin#run.test-run-goal.optional-parameters] -* xref:maven-plugin:run.adoc#run.test-run-goal.parameter-details[maven-plugin#run.test-run-goal.parameter-details] * xref:maven-plugin:run.adoc#run.test-run-goal.parameter-details.add-resources[maven-plugin#run.test-run-goal.parameter-details.add-resources] * xref:maven-plugin:run.adoc#run.test-run-goal.parameter-details.additional-classpath-elements[maven-plugin#run.test-run-goal.parameter-details.additional-classpath-elements] * xref:maven-plugin:run.adoc#run.test-run-goal.parameter-details.agents[maven-plugin#run.test-run-goal.parameter-details.agents] @@ -725,151 +967,262 @@ * xref:maven-plugin:run.adoc#run.test-run-goal.parameter-details.system-property-variables[maven-plugin#run.test-run-goal.parameter-details.system-property-variables] * xref:maven-plugin:run.adoc#run.test-run-goal.parameter-details.test-classes-directory[maven-plugin#run.test-run-goal.parameter-details.test-classes-directory] * xref:maven-plugin:run.adoc#run.test-run-goal.parameter-details.working-directory[maven-plugin#run.test-run-goal.parameter-details.working-directory] +* xref:maven-plugin:run.adoc#run.test-run-goal.parameter-details[maven-plugin#run.test-run-goal.parameter-details] * xref:maven-plugin:run.adoc#run.test-run-goal.required-parameters[maven-plugin#run.test-run-goal.required-parameters] -* xref:maven-plugin:using.adoc#using[maven-plugin#using] +* xref:maven-plugin:run.adoc#run.test-run-goal[maven-plugin#run.test-run-goal] +* xref:maven-plugin:run.adoc#run[maven-plugin#run] * xref:maven-plugin:using.adoc#using.import[maven-plugin#using.import] * xref:maven-plugin:using.adoc#using.overriding-command-line[maven-plugin#using.overriding-command-line] * xref:maven-plugin:using.adoc#using.parent-pom[maven-plugin#using.parent-pom] -* xref:reference:actuator/auditing.adoc#actuator.auditing[#actuator.auditing] +* xref:maven-plugin:using.adoc#using[maven-plugin#using] * xref:reference:actuator/auditing.adoc#actuator.auditing.custom[#actuator.auditing.custom] -* xref:reference:actuator/cloud-foundry.adoc#actuator.cloud-foundry[#actuator.cloud-foundry] +* xref:reference:actuator/auditing.adoc#actuator.auditing.custom[#production-ready-auditing-custom] +* xref:reference:actuator/auditing.adoc#actuator.auditing[#actuator.auditing] +* xref:reference:actuator/auditing.adoc#actuator.auditing[#production-ready-auditing] * xref:reference:actuator/cloud-foundry.adoc#actuator.cloud-foundry.custom-context-path[#actuator.cloud-foundry.custom-context-path] +* xref:reference:actuator/cloud-foundry.adoc#actuator.cloud-foundry.custom-context-path[#production-ready-custom-context-path] * xref:reference:actuator/cloud-foundry.adoc#actuator.cloud-foundry.disable[#actuator.cloud-foundry.disable] +* xref:reference:actuator/cloud-foundry.adoc#actuator.cloud-foundry.disable[#production-ready-cloudfoundry-disable] * xref:reference:actuator/cloud-foundry.adoc#actuator.cloud-foundry.ssl[#actuator.cloud-foundry.ssl] +* xref:reference:actuator/cloud-foundry.adoc#actuator.cloud-foundry.ssl[#production-ready-cloudfoundry-ssl] +* xref:reference:actuator/cloud-foundry.adoc#actuator.cloud-foundry[#actuator.cloud-foundry] +* xref:reference:actuator/cloud-foundry.adoc#actuator.cloud-foundry[#production-ready-cloudfoundry] * xref:reference:actuator/enabling.adoc#actuator.enabling[#actuator.enabling] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints[#actuator.endpoints] +* xref:reference:actuator/enabling.adoc#actuator.enabling[#production-ready-enabling] * xref:reference:actuator/endpoints.adoc#actuator.endpoints.caching[#actuator.endpoints.caching] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.caching[#production-ready-endpoints-caching] * xref:reference:actuator/endpoints.adoc#actuator.endpoints.cors[#actuator.endpoints.cors] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.cors[#production-ready-endpoints-cors] * xref:reference:actuator/endpoints.adoc#actuator.endpoints.enabling[#actuator.endpoints.enabling] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.enabling[#production-ready-endpoints-enabling-endpoints] * xref:reference:actuator/endpoints.adoc#actuator.endpoints.exposing[#actuator.endpoints.exposing] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.health[#actuator.endpoints.health] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.exposing[#production-ready-endpoints-exposing-endpoints] * xref:reference:actuator/endpoints.adoc#actuator.endpoints.health.auto-configured-health-indicators[#actuator.endpoints.health.auto-configured-health-indicators] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.health.auto-configured-health-indicators[#production-ready-health-indicators] * xref:reference:actuator/endpoints.adoc#actuator.endpoints.health.auto-configured-reactive-health-indicators[#actuator.endpoints.health.auto-configured-reactive-health-indicators] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.health.auto-configured-reactive-health-indicators[#reactive-health-indicators-autoconfigured] * xref:reference:actuator/endpoints.adoc#actuator.endpoints.health.datasource[#actuator.endpoints.health.datasource] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.health.datasource[#production-ready-health-datasource] * xref:reference:actuator/endpoints.adoc#actuator.endpoints.health.groups[#actuator.endpoints.health.groups] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.health.groups[#production-ready-health-groups] * xref:reference:actuator/endpoints.adoc#actuator.endpoints.health.reactive-health-indicators[#actuator.endpoints.health.reactive-health-indicators] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.health.reactive-health-indicators[#reactive-health-indicators] * xref:reference:actuator/endpoints.adoc#actuator.endpoints.health.writing-custom-health-indicators[#actuator.endpoints.health.writing-custom-health-indicators] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.health.writing-custom-health-indicators[#production-ready-health-indicators-writing] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.health[#actuator.endpoints.health] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.health[#production-ready-health] * xref:reference:actuator/endpoints.adoc#actuator.endpoints.hypermedia[#actuator.endpoints.hypermedia] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom[#actuator.endpoints.implementing-custom] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.input[#actuator.endpoints.implementing-custom.input] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.hypermedia[#production-ready-endpoints-hypermedia] * xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.input.conversion[#actuator.endpoints.implementing-custom.input.conversion] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web[#actuator.endpoints.implementing-custom.web] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.input.conversion[#production-ready-endpoints-custom-input-conversion] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.input[#actuator.endpoints.implementing-custom.input] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.input[#production-ready-endpoints-custom-input] * xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.consumes-predicates[#actuator.endpoints.implementing-custom.web.consumes-predicates] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.consumes-predicates[#production-ready-endpoints-custom-web-predicate-consumes] * xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.method-predicates[#actuator.endpoints.implementing-custom.web.method-predicates] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.method-predicates[#production-ready-endpoints-custom-web-predicate-http-method] * xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.path-predicates[#actuator.endpoints.implementing-custom.web.path-predicates] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.path-predicates[#production-ready-endpoints-custom-web-predicate-path] * xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.produces-predicates[#actuator.endpoints.implementing-custom.web.produces-predicates] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.produces-predicates[#production-ready-endpoints-custom-web-predicate-produces] * xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.range-requests[#actuator.endpoints.implementing-custom.web.range-requests] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.range-requests[#production-ready-endpoints-custom-web-range-requests] * xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.request-predicates[#actuator.endpoints.implementing-custom.web.request-predicates] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.request-predicates[#production-ready-endpoints-custom-web-predicate] * xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.response-status[#actuator.endpoints.implementing-custom.web.response-status] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.response-status[#production-ready-endpoints-custom-web-response-status] * xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.security[#actuator.endpoints.implementing-custom.web.security] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.info[#actuator.endpoints.info] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.security[#production-ready-endpoints-custom-web-security] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web[#actuator.endpoints.implementing-custom.web] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web[#production-ready-endpoints-custom-web] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom[#actuator.endpoints.implementing-custom] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom[#production-ready-endpoints-custom] * xref:reference:actuator/endpoints.adoc#actuator.endpoints.info.auto-configured-info-contributors[#actuator.endpoints.info.auto-configured-info-contributors] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.info.auto-configured-info-contributors[#production-ready-application-info-autoconfigure] * xref:reference:actuator/endpoints.adoc#actuator.endpoints.info.build-information[#actuator.endpoints.info.build-information] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.info.build-information[#production-ready-application-info-build] * xref:reference:actuator/endpoints.adoc#actuator.endpoints.info.custom-application-information[#actuator.endpoints.info.custom-application-information] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.info.custom-application-information[#production-ready-application-info-env] * xref:reference:actuator/endpoints.adoc#actuator.endpoints.info.git-commit-information[#actuator.endpoints.info.git-commit-information] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.info.git-commit-information[#production-ready-application-info-git] * xref:reference:actuator/endpoints.adoc#actuator.endpoints.info.java-information[#actuator.endpoints.info.java-information] * xref:reference:actuator/endpoints.adoc#actuator.endpoints.info.os-information[#actuator.endpoints.info.os-information] * xref:reference:actuator/endpoints.adoc#actuator.endpoints.info.process-information[#actuator.endpoints.info.process-information] * xref:reference:actuator/endpoints.adoc#actuator.endpoints.info.writing-custom-info-contributors[#actuator.endpoints.info.writing-custom-info-contributors] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.kubernetes-probes[#actuator.endpoints.kubernetes-probes] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.info.writing-custom-info-contributors[#production-ready-application-info-custom] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.info[#actuator.endpoints.info] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.info[#production-ready-application-info] * xref:reference:actuator/endpoints.adoc#actuator.endpoints.kubernetes-probes.external-state[#actuator.endpoints.kubernetes-probes.external-state] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.kubernetes-probes.external-state[#production-ready-kubernetes-probes-external-state] * xref:reference:actuator/endpoints.adoc#actuator.endpoints.kubernetes-probes.lifecycle[#actuator.endpoints.kubernetes-probes.lifecycle] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.sanitization[#howto-sanitize-sensitive-values] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.sanitization[#actuator.endpoints.sanitization] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.sanitization[#howto-sanitize-sensible-values] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.sbom[#actuator.endpoints.sbom] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.kubernetes-probes.lifecycle[#production-ready-kubernetes-probes-lifecycle] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.kubernetes-probes[#actuator.endpoints.kubernetes-probes] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.kubernetes-probes[#production-ready-kubernetes-probes] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.sanitization[#actuator.endpoints.sanitization] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.sanitization[#howto-sanitize-sensible-values] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.sanitization[#howto-sanitize-sensitive-values] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.sanitization[#howto.actuator.sanitize-sensitive-values] * xref:reference:actuator/endpoints.adoc#actuator.endpoints.sbom.additional[#actuator.endpoints.sbom.additional] * xref:reference:actuator/endpoints.adoc#actuator.endpoints.sbom.other-formats[#actuator.endpoints.sbom.other-formats] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.sbom[#actuator.endpoints.sbom] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.security.csrf[#actuator.endpoints.security.csrf] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.security.csrf[#boot-features-security-csrf] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.security.csrf[#features.security.actuator.csrf] * xref:reference:actuator/endpoints.adoc#actuator.endpoints.security[#actuator.endpoints.security] * xref:reference:actuator/endpoints.adoc#actuator.endpoints.security[#boot-features-security-actuator] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.security.csrf[#boot-features-security-csrf] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.security.csrf[#actuator.endpoints.security.csrf] -* xref:reference:actuator/http-exchanges.adoc#actuator.http-exchanges[#production-ready-http-tracing] -* xref:reference:actuator/http-exchanges.adoc#actuator.http-exchanges[#actuator.http-exchanges] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints.security[#production-ready-endpoints-security] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints[#actuator.endpoints] +* xref:reference:actuator/endpoints.adoc#actuator.endpoints[#production-ready-endpoints] * xref:reference:actuator/http-exchanges.adoc#actuator.http-exchanges.custom[#actuator.http-exchanges.custom] +* xref:reference:actuator/http-exchanges.adoc#actuator.http-exchanges.custom[#actuator.tracing.custom] * xref:reference:actuator/http-exchanges.adoc#actuator.http-exchanges.custom[#production-ready-http-tracing-custom] +* xref:reference:actuator/http-exchanges.adoc#actuator.http-exchanges[#actuator.http-exchanges] +* xref:reference:actuator/http-exchanges.adoc#actuator.http-exchanges[#actuator.tracing] +* xref:reference:actuator/http-exchanges.adoc#actuator.http-exchanges[#production-ready-http-tracing] * xref:reference:actuator/index.adoc#actuator[#actuator] -* xref:reference:actuator/jmx.adoc#actuator.jmx[#actuator.jmx] -* xref:reference:actuator/jmx.adoc#actuator.jmx[#boot-features-jmx] +* xref:reference:actuator/index.adoc#actuator[#production-ready] +* xref:reference:actuator/index.adoc[#actuator] +* xref:reference:actuator/index.adoc[actuator] * xref:reference:actuator/jmx.adoc#actuator.jmx.custom-mbean-names[#actuator.jmx.custom-mbean-names] +* xref:reference:actuator/jmx.adoc#actuator.jmx.custom-mbean-names[#production-ready-custom-mbean-names] * xref:reference:actuator/jmx.adoc#actuator.jmx.disable-jmx-endpoints[#actuator.jmx.disable-jmx-endpoints] -* xref:reference:actuator/loggers.adoc#actuator.loggers[#actuator.loggers] +* xref:reference:actuator/jmx.adoc#actuator.jmx.disable-jmx-endpoints[#production-ready-disable-jmx-endpoints] +* xref:reference:actuator/jmx.adoc#actuator.jmx[#actuator.jmx] +* xref:reference:actuator/jmx.adoc#actuator.jmx[#boot-features-jmx] +* xref:reference:actuator/jmx.adoc#actuator.jmx[#production-ready-jmx] * xref:reference:actuator/loggers.adoc#actuator.loggers.configure[#actuator.loggers.configure] -* xref:reference:actuator/metrics.adoc#actuator.metrics[#actuator.metrics] -* xref:reference:actuator/metrics.adoc#actuator.metrics.customizing[#actuator.metrics.customizing] +* xref:reference:actuator/loggers.adoc#actuator.loggers.configure[#production-ready-logger-configuration] +* xref:reference:actuator/loggers.adoc#actuator.loggers[#actuator.loggers] +* xref:reference:actuator/loggers.adoc#actuator.loggers[#production-ready-loggers] * xref:reference:actuator/metrics.adoc#actuator.metrics.customizing.common-tags[#actuator.metrics.customizing.common-tags] +* xref:reference:actuator/metrics.adoc#actuator.metrics.customizing.common-tags[#production-ready-metrics-common-tags] * xref:reference:actuator/metrics.adoc#actuator.metrics.customizing.per-meter-properties[#actuator.metrics.customizing.per-meter-properties] +* xref:reference:actuator/metrics.adoc#actuator.metrics.customizing.per-meter-properties[#production-ready-metrics-per-meter-properties] +* xref:reference:actuator/metrics.adoc#actuator.metrics.customizing[#actuator.metrics.customizing] +* xref:reference:actuator/metrics.adoc#actuator.metrics.customizing[#production-ready-metrics-customizing] * xref:reference:actuator/metrics.adoc#actuator.metrics.endpoint[#actuator.metrics.endpoint] -* xref:reference:actuator/metrics.adoc#actuator.metrics.export[#actuator.metrics.export] +* xref:reference:actuator/metrics.adoc#actuator.metrics.endpoint[#production-ready-metrics-endpoint] * xref:reference:actuator/metrics.adoc#actuator.metrics.export.appoptics[#actuator.metrics.export.appoptics] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export.appoptics[#production-ready-metrics-export-appoptics] * xref:reference:actuator/metrics.adoc#actuator.metrics.export.atlas[#actuator.metrics.export.atlas] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export.atlas[#production-ready-metrics-export-atlas] * xref:reference:actuator/metrics.adoc#actuator.metrics.export.datadog[#actuator.metrics.export.datadog] -* xref:reference:actuator/metrics.adoc#actuator.metrics.export.dynatrace[#actuator.metrics.export.dynatrace] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export.datadog[#production-ready-metrics-export-datadog] * xref:reference:actuator/metrics.adoc#actuator.metrics.export.dynatrace.v1-api[#actuator.metrics.export.dynatrace.v1-api] -* xref:reference:actuator/metrics.adoc#actuator.metrics.export.dynatrace.v2-api[#actuator.metrics.export.dynatrace.v2-api] * xref:reference:actuator/metrics.adoc#actuator.metrics.export.dynatrace.v2-api.auto-config[#actuator.metrics.export.dynatrace.v2-api.auto-config] * xref:reference:actuator/metrics.adoc#actuator.metrics.export.dynatrace.v2-api.manual-config[#actuator.metrics.export.dynatrace.v2-api.manual-config] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export.dynatrace.v2-api[#actuator.metrics.export.dynatrace.v2-api] * xref:reference:actuator/metrics.adoc#actuator.metrics.export.dynatrace.version-independent-settings[#actuator.metrics.export.dynatrace.version-independent-settings] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export.dynatrace[#actuator.metrics.export.dynatrace] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export.dynatrace[#production-ready-metrics-export-dynatrace] * xref:reference:actuator/metrics.adoc#actuator.metrics.export.elastic[#actuator.metrics.export.elastic] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export.elastic[#production-ready-metrics-export-elastic] * xref:reference:actuator/metrics.adoc#actuator.metrics.export.ganglia[#actuator.metrics.export.ganglia] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export.ganglia[#production-ready-metrics-export-ganglia] * xref:reference:actuator/metrics.adoc#actuator.metrics.export.graphite[#actuator.metrics.export.graphite] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export.graphite[#production-ready-metrics-export-graphite] * xref:reference:actuator/metrics.adoc#actuator.metrics.export.humio[#actuator.metrics.export.humio] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export.humio[#production-ready-metrics-export-humio] * xref:reference:actuator/metrics.adoc#actuator.metrics.export.influx[#actuator.metrics.export.influx] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export.influx[#production-ready-metrics-export-influx] * xref:reference:actuator/metrics.adoc#actuator.metrics.export.jmx[#actuator.metrics.export.jmx] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export.jmx[#production-ready-metrics-export-jmx] * xref:reference:actuator/metrics.adoc#actuator.metrics.export.kairos[#actuator.metrics.export.kairos] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export.kairos[#production-ready-metrics-export-kairos] * xref:reference:actuator/metrics.adoc#actuator.metrics.export.newrelic[#actuator.metrics.export.newrelic] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export.newrelic[#production-ready-metrics-export-newrelic] * xref:reference:actuator/metrics.adoc#actuator.metrics.export.otlp[#actuator.metrics.export.otlp] * xref:reference:actuator/metrics.adoc#actuator.metrics.export.prometheus[#actuator.metrics.export.prometheus] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export.prometheus[#production-ready-metrics-export-prometheus] * xref:reference:actuator/metrics.adoc#actuator.metrics.export.signalfx[#actuator.metrics.export.signalfx] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export.signalfx[#production-ready-metrics-export-signalfx] * xref:reference:actuator/metrics.adoc#actuator.metrics.export.simple[#actuator.metrics.export.simple] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export.simple[#production-ready-metrics-export-simple] * xref:reference:actuator/metrics.adoc#actuator.metrics.export.stackdriver[#actuator.metrics.export.stackdriver] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export.stackdriver[#production-ready-metrics-export-stackdriver] * xref:reference:actuator/metrics.adoc#actuator.metrics.export.statsd[#actuator.metrics.export.statsd] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export.statsd[#production-ready-metrics-export-statsd] * xref:reference:actuator/metrics.adoc#actuator.metrics.export.wavefront[#actuator.metrics.export.wavefront] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export.wavefront[#production-ready-metrics-export-wavefront] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export[#actuator.metrics.export] +* xref:reference:actuator/metrics.adoc#actuator.metrics.export[#production-ready-metrics-export] * xref:reference:actuator/metrics.adoc#actuator.metrics.getting-started[#actuator.metrics.getting-started] +* xref:reference:actuator/metrics.adoc#actuator.metrics.getting-started[#production-ready-metrics-getting-started] * xref:reference:actuator/metrics.adoc#actuator.metrics.micrometer-observation[#actuator.metrics.micrometer-observation] * xref:reference:actuator/metrics.adoc#actuator.metrics.registering-custom[#actuator.metrics.registering-custom] -* xref:reference:actuator/metrics.adoc#actuator.metrics.supported[#actuator.metrics.supported] +* xref:reference:actuator/metrics.adoc#actuator.metrics.registering-custom[#production-ready-metrics-custom] * xref:reference:actuator/metrics.adoc#actuator.metrics.supported.application-startup[#actuator.metrics.supported.application-startup] * xref:reference:actuator/metrics.adoc#actuator.metrics.supported.cache[#actuator.metrics.supported.cache] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.cache[#production-ready-metrics-cache] * xref:reference:actuator/metrics.adoc#actuator.metrics.supported.hibernate[#actuator.metrics.supported.hibernate] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.hibernate[#production-ready-metrics-hibernate] * xref:reference:actuator/metrics.adoc#actuator.metrics.supported.http-clients[#actuator.metrics.supported.http-clients] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.http-clients[#production-ready-metrics-http-clients] * xref:reference:actuator/metrics.adoc#actuator.metrics.supported.jdbc[#actuator.metrics.supported.jdbc] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.jdbc[#production-ready-metrics-jdbc] * xref:reference:actuator/metrics.adoc#actuator.metrics.supported.jersey[#actuator.metrics.supported.jersey] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.jersey[#production-ready-metrics-jersey-server] * xref:reference:actuator/metrics.adoc#actuator.metrics.supported.jetty[#actuator.metrics.supported.jetty] * xref:reference:actuator/metrics.adoc#actuator.metrics.supported.jms[#actuator.metrics.supported.jms] * xref:reference:actuator/metrics.adoc#actuator.metrics.supported.jvm[#actuator.metrics.supported.jvm] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.jvm[#production-ready-metrics-jvm] * xref:reference:actuator/metrics.adoc#actuator.metrics.supported.kafka[#actuator.metrics.supported.kafka] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.kafka[#production-ready-metrics-kafka] * xref:reference:actuator/metrics.adoc#actuator.metrics.supported.logger[#actuator.metrics.supported.logger] -* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.mongodb[#actuator.metrics.supported.mongodb] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.logger[#production-ready-metrics-logger] * xref:reference:actuator/metrics.adoc#actuator.metrics.supported.mongodb.command[#actuator.metrics.supported.mongodb.command] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.mongodb.command[#production-ready-metrics-mongodb-command] * xref:reference:actuator/metrics.adoc#actuator.metrics.supported.mongodb.connection-pool[#actuator.metrics.supported.mongodb.connection-pool] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.mongodb.connection-pool[#production-ready-metrics-mongodb-connectionpool] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.mongodb[#actuator.metrics.supported.mongodb] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.mongodb[#production-ready-metrics-mongodb] * xref:reference:actuator/metrics.adoc#actuator.metrics.supported.rabbitmq[#actuator.metrics.supported.rabbitmq] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.rabbitmq[#production-ready-metrics-rabbitmq] * xref:reference:actuator/metrics.adoc#actuator.metrics.supported.redis[#actuator.metrics.supported.redis] * xref:reference:actuator/metrics.adoc#actuator.metrics.supported.spring-batch[#actuator.metrics.supported.spring-batch] * xref:reference:actuator/metrics.adoc#actuator.metrics.supported.spring-data-repository[#actuator.metrics.supported.spring-data-repository] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.spring-data-repository[#production-ready-metrics-data-repository] * xref:reference:actuator/metrics.adoc#actuator.metrics.supported.spring-graphql[#actuator.metrics.supported.spring-graphql] * xref:reference:actuator/metrics.adoc#actuator.metrics.supported.spring-integration[#actuator.metrics.supported.spring-integration] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.spring-integration[#production-ready-metrics-integration] * xref:reference:actuator/metrics.adoc#actuator.metrics.supported.spring-mvc[#actuator.metrics.supported.spring-mvc] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.spring-mvc[#production-ready-metrics-spring-mvc] * xref:reference:actuator/metrics.adoc#actuator.metrics.supported.spring-webflux[#actuator.metrics.supported.spring-webflux] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.spring-webflux[#production-ready-metrics-web-flux] * xref:reference:actuator/metrics.adoc#actuator.metrics.supported.system[#actuator.metrics.supported.system] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.system[#production-ready-metrics-system] * xref:reference:actuator/metrics.adoc#actuator.metrics.supported.tasks[#actuator.metrics.supported.tasks] * xref:reference:actuator/metrics.adoc#actuator.metrics.supported.timed-annotation[#actuator.metrics.supported.timed-annotation] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.timed-annotation[#production-ready-metrics-timed-annotation] * xref:reference:actuator/metrics.adoc#actuator.metrics.supported.tomcat[#actuator.metrics.supported.tomcat] -* xref:reference:actuator/monitoring.adoc#actuator.monitoring[#actuator.monitoring] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.tomcat[#production-ready-metrics-tomcat] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported[#actuator.metrics.supported] +* xref:reference:actuator/metrics.adoc#actuator.metrics.supported[#production-ready-metrics-meter] +* xref:reference:actuator/metrics.adoc#actuator.metrics[#actuator.metrics] +* xref:reference:actuator/metrics.adoc#actuator.metrics[#production-ready-metrics] * xref:reference:actuator/monitoring.adoc#actuator.monitoring.customizing-management-server-address[#actuator.monitoring.customizing-management-server-address] +* xref:reference:actuator/monitoring.adoc#actuator.monitoring.customizing-management-server-address[#production-ready-customizing-management-server-address] * xref:reference:actuator/monitoring.adoc#actuator.monitoring.customizing-management-server-context-path[#actuator.monitoring.customizing-management-server-context-path] +* xref:reference:actuator/monitoring.adoc#actuator.monitoring.customizing-management-server-context-path[#production-ready-customizing-management-server-context-path] * xref:reference:actuator/monitoring.adoc#actuator.monitoring.customizing-management-server-port[#actuator.monitoring.customizing-management-server-port] +* xref:reference:actuator/monitoring.adoc#actuator.monitoring.customizing-management-server-port[#production-ready-customizing-management-server-port] * xref:reference:actuator/monitoring.adoc#actuator.monitoring.disabling-http-endpoints[#actuator.monitoring.disabling-http-endpoints] +* xref:reference:actuator/monitoring.adoc#actuator.monitoring.disabling-http-endpoints[#production-ready-disabling-http-endpoints] * xref:reference:actuator/monitoring.adoc#actuator.monitoring.management-specific-ssl[#actuator.monitoring.management-specific-ssl] -* xref:reference:actuator/observability.adoc#actuator.observability[#actuator.observability] +* xref:reference:actuator/monitoring.adoc#actuator.monitoring.management-specific-ssl[#production-ready-management-specific-ssl] +* xref:reference:actuator/monitoring.adoc#actuator.monitoring[#actuator.monitoring] +* xref:reference:actuator/monitoring.adoc#actuator.monitoring[#production-ready-monitoring] * xref:reference:actuator/observability.adoc#actuator.observability.annotations[#actuator.observability.annotations] * xref:reference:actuator/observability.adoc#actuator.observability.common-tags[#actuator.observability.common-tags] * xref:reference:actuator/observability.adoc#actuator.observability.opentelemetry[#actuator.observability.opentelemetry] * xref:reference:actuator/observability.adoc#actuator.observability.preventing-observations[#actuator.observability.preventing-observations] -* xref:reference:actuator/process-monitoring.adoc#actuator.process-monitoring[#actuator.process-monitoring] +* xref:reference:actuator/observability.adoc#actuator.observability[#actuator.observability] * xref:reference:actuator/process-monitoring.adoc#actuator.process-monitoring.configuration[#actuator.process-monitoring.configuration] +* xref:reference:actuator/process-monitoring.adoc#actuator.process-monitoring.configuration[#production-ready-process-monitoring-configuration] * xref:reference:actuator/process-monitoring.adoc#actuator.process-monitoring.programmatically[#actuator.process-monitoring.programmatically] -* xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing[#actuator.micrometer-tracing] +* xref:reference:actuator/process-monitoring.adoc#actuator.process-monitoring.programmatically[#production-ready-process-monitoring-programmatically] +* xref:reference:actuator/process-monitoring.adoc#actuator.process-monitoring[#actuator.process-monitoring] +* xref:reference:actuator/process-monitoring.adoc#actuator.process-monitoring[#production-ready-process-monitoring] * xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing.baggage[#actuator.micrometer-tracing.baggage] * xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing.creating-spans[#actuator.micrometer-tracing.creating-spans] * xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing.getting-started[#actuator.micrometer-tracing.getting-started] @@ -877,1477 +1230,1118 @@ * xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing.micrometer-observation[#actuator.micrometer-tracing.micrometer-observation] * xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing.propagating-traces[#actuator.micrometer-tracing.propagating-traces] * xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing.tests[#actuator.micrometer-tracing.tests] -* xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing.tracer-implementations[#actuator.micrometer-tracing.tracer-implementations] * xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing.tracer-implementations.brave-wavefront[#actuator.micrometer-tracing.tracer-implementations.brave-wavefront] * xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing.tracer-implementations.brave-zipkin[#actuator.micrometer-tracing.tracer-implementations.brave-zipkin] * xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing.tracer-implementations.otel-otlp[#actuator.micrometer-tracing.tracer-implementations.otel-otlp] * xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing.tracer-implementations.otel-wavefront[#actuator.micrometer-tracing.tracer-implementations.otel-wavefront] * xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing.tracer-implementations.otel-zipkin[#actuator.micrometer-tracing.tracer-implementations.otel-zipkin] +* xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing.tracer-implementations[#actuator.micrometer-tracing.tracer-implementations] * xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing.tracers[#actuator.micrometer-tracing.tracers] -* xref:reference:packaging/container-images/cloud-native-buildpacks.adoc#packaging.container-images.buildpacks[#boot-features-container-images-buildpacks] -* xref:reference:packaging/container-images/cloud-native-buildpacks.adoc#packaging.container-images.buildpacks[#container-images.buildpacks] -* xref:reference:packaging/container-images/dockerfiles.adoc#packaging.container-images.dockerfiles[#container-images.dockerfiles] -* xref:reference:packaging/container-images/dockerfiles.adoc#packaging.container-images.dockerfiles[#boot-features-container-images-docker] -* xref:reference:packaging/container-images/efficient-images.adoc#packaging.container-images.efficient-images[#container-images.efficient-images] -* xref:reference:packaging/container-images/efficient-images.adoc#packaging.container-images.efficient-images[#boot-features-container-images] -* xref:reference:packaging/container-images/efficient-images.adoc#packaging.container-images.efficient-images[#boot-features-container-images-building] -* xref:reference:packaging/container-images/efficient-images.adoc#packaging.container-images.efficient-images.layering[#container-images.efficient-images.layering] -* xref:reference:packaging/container-images/efficient-images.adoc#packaging.container-images.efficient-images.layering[#boot-layering-docker-images] -* xref:reference:packaging/container-images/index.adoc#packaging.container-images[#container-images] +* xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing[#actuator.micrometer-tracing] * xref:reference:data/index.adoc#data[#data] -* xref:reference:data/nosql.adoc#data.nosql[#boot-features-nosql] -* xref:reference:data/nosql.adoc#data.nosql[#data.nosql] -* xref:reference:data/nosql.adoc#data.nosql.cassandra[#data.nosql.cassandra] -* xref:reference:data/nosql.adoc#data.nosql.cassandra[#boot-features-cassandra] -* xref:reference:data/nosql.adoc#data.nosql.cassandra.connecting[#data.nosql.cassandra.connecting] +* xref:reference:data/index.adoc[#data] +* xref:reference:data/index.adoc[data] * xref:reference:data/nosql.adoc#data.nosql.cassandra.connecting[#boot-features-connecting-to-cassandra] -* xref:reference:data/nosql.adoc#data.nosql.cassandra.repositories[#data.nosql.cassandra.repositories] +* xref:reference:data/nosql.adoc#data.nosql.cassandra.connecting[#data.nosql.cassandra.connecting] +* xref:reference:data/nosql.adoc#data.nosql.cassandra.connecting[#features.nosql.cassandra.connecting] * xref:reference:data/nosql.adoc#data.nosql.cassandra.repositories[#boot-features-spring-data-cassandra-repositories] -* xref:reference:data/nosql.adoc#data.nosql.couchbase[#data.nosql.couchbase] -* xref:reference:data/nosql.adoc#data.nosql.couchbase[#boot-features-couchbase] +* xref:reference:data/nosql.adoc#data.nosql.cassandra.repositories[#data.nosql.cassandra.repositories] +* xref:reference:data/nosql.adoc#data.nosql.cassandra.repositories[#features.nosql.cassandra.repositories] +* xref:reference:data/nosql.adoc#data.nosql.cassandra[#boot-features-cassandra] +* xref:reference:data/nosql.adoc#data.nosql.cassandra[#data.nosql.cassandra] +* xref:reference:data/nosql.adoc#data.nosql.cassandra[#features.nosql.cassandra] * xref:reference:data/nosql.adoc#data.nosql.couchbase.connecting[#boot-features-connecting-to-couchbase] * xref:reference:data/nosql.adoc#data.nosql.couchbase.connecting[#data.nosql.couchbase.connecting] +* xref:reference:data/nosql.adoc#data.nosql.couchbase.connecting[#features.nosql.couchbase.connecting] * xref:reference:data/nosql.adoc#data.nosql.couchbase.repositories[#boot-features-spring-data-couchbase-repositories] * xref:reference:data/nosql.adoc#data.nosql.couchbase.repositories[#data.nosql.couchbase.repositories] -* xref:reference:data/nosql.adoc#data.nosql.elasticsearch[#data.nosql.elasticsearch] -* xref:reference:data/nosql.adoc#data.nosql.elasticsearch[#boot-features-elasticsearch] -* xref:reference:data/nosql.adoc#data.nosql.elasticsearch[#boot-features-connecting-to-elasticsearch-reactive-rest] -* xref:reference:data/nosql.adoc#data.nosql.elasticsearch.connecting-using-rest[#boot-features-connecting-to-elasticsearch-rest] -* xref:reference:data/nosql.adoc#data.nosql.elasticsearch.connecting-using-rest[#data.nosql.elasticsearch.connecting-using-rest] +* xref:reference:data/nosql.adoc#data.nosql.couchbase.repositories[#features.nosql.couchbase.repositories] +* xref:reference:data/nosql.adoc#data.nosql.couchbase[#boot-features-couchbase] +* xref:reference:data/nosql.adoc#data.nosql.couchbase[#data.nosql.couchbase] +* xref:reference:data/nosql.adoc#data.nosql.couchbase[#features.nosql.couchbase] * xref:reference:data/nosql.adoc#data.nosql.elasticsearch.connecting-using-rest.javaapiclient[#data.nosql.elasticsearch.connecting-using-rest.javaapiclient] * xref:reference:data/nosql.adoc#data.nosql.elasticsearch.connecting-using-rest.reactiveclient[#data.nosql.elasticsearch.connecting-using-rest.reactiveclient] +* xref:reference:data/nosql.adoc#data.nosql.elasticsearch.connecting-using-rest.reactiveclient[#data.nosql.elasticsearch.connecting-using-rest.webclient] * xref:reference:data/nosql.adoc#data.nosql.elasticsearch.connecting-using-rest.restclient[#data.nosql.elasticsearch.connecting-using-rest.restclient] -* xref:reference:data/nosql.adoc#data.nosql.elasticsearch.connecting-using-spring-data[#data.nosql.elasticsearch.connecting-using-spring-data] +* xref:reference:data/nosql.adoc#data.nosql.elasticsearch.connecting-using-rest[#boot-features-connecting-to-elasticsearch-rest] +* xref:reference:data/nosql.adoc#data.nosql.elasticsearch.connecting-using-rest[#data.nosql.elasticsearch.connecting-using-reactive-rest] +* xref:reference:data/nosql.adoc#data.nosql.elasticsearch.connecting-using-rest[#data.nosql.elasticsearch.connecting-using-rest] +* xref:reference:data/nosql.adoc#data.nosql.elasticsearch.connecting-using-rest[#features.nosql.elasticsearch.connecting-using-rest] * xref:reference:data/nosql.adoc#data.nosql.elasticsearch.connecting-using-spring-data[#boot-features-connecting-to-elasticsearch-spring-data] -* xref:reference:data/nosql.adoc#data.nosql.elasticsearch.repositories[#data.nosql.elasticsearch.repositories] +* xref:reference:data/nosql.adoc#data.nosql.elasticsearch.connecting-using-spring-data[#data.nosql.elasticsearch.connecting-using-spring-data] +* xref:reference:data/nosql.adoc#data.nosql.elasticsearch.connecting-using-spring-data[#features.nosql.elasticsearch.connecting-using-spring-data] * xref:reference:data/nosql.adoc#data.nosql.elasticsearch.repositories[#boot-features-spring-data-elasticsearch-repositories] +* xref:reference:data/nosql.adoc#data.nosql.elasticsearch.repositories[#data.nosql.elasticsearch.repositories] +* xref:reference:data/nosql.adoc#data.nosql.elasticsearch.repositories[#features.nosql.elasticsearch.repositories] +* xref:reference:data/nosql.adoc#data.nosql.elasticsearch[#boot-features-connecting-to-elasticsearch-reactive-rest] +* xref:reference:data/nosql.adoc#data.nosql.elasticsearch[#boot-features-elasticsearch] +* xref:reference:data/nosql.adoc#data.nosql.elasticsearch[#data.nosql.elasticsearch] +* xref:reference:data/nosql.adoc#data.nosql.elasticsearch[#features.nosql.elasticsearch] +* xref:reference:data/nosql.adoc#data.nosql.influxdb.connecting[#boot-features-connecting-to-influxdb] +* xref:reference:data/nosql.adoc#data.nosql.influxdb.connecting[#data.nosql.influxdb.connecting] +* xref:reference:data/nosql.adoc#data.nosql.influxdb.connecting[#features.nosql.influxdb.connecting] * xref:reference:data/nosql.adoc#data.nosql.influxdb[#boot-features-influxdb] * xref:reference:data/nosql.adoc#data.nosql.influxdb[#data.nosql.influxdb] -* xref:reference:data/nosql.adoc#data.nosql.influxdb.connecting[#data.nosql.influxdb.connecting] -* xref:reference:data/nosql.adoc#data.nosql.influxdb.connecting[#boot-features-connecting-to-influxdb] -* xref:reference:data/nosql.adoc#data.nosql.ldap[#boot-features-ldap] -* xref:reference:data/nosql.adoc#data.nosql.ldap[#data.nosql.ldap] +* xref:reference:data/nosql.adoc#data.nosql.influxdb[#features.nosql.influxdb] * xref:reference:data/nosql.adoc#data.nosql.ldap.connecting[#boot-features-ldap-connecting] * xref:reference:data/nosql.adoc#data.nosql.ldap.connecting[#data.nosql.ldap.connecting] -* xref:reference:data/nosql.adoc#data.nosql.ldap.embedded[#data.nosql.ldap.embedded] +* xref:reference:data/nosql.adoc#data.nosql.ldap.connecting[#features.nosql.ldap.connecting] * xref:reference:data/nosql.adoc#data.nosql.ldap.embedded[#boot-features-ldap-embedded] +* xref:reference:data/nosql.adoc#data.nosql.ldap.embedded[#data.nosql.ldap.embedded] +* xref:reference:data/nosql.adoc#data.nosql.ldap.embedded[#features.nosql.ldap.embedded] * xref:reference:data/nosql.adoc#data.nosql.ldap.repositories[#boot-features-ldap-spring-data-repositories] * xref:reference:data/nosql.adoc#data.nosql.ldap.repositories[#data.nosql.ldap.repositories] -* xref:reference:data/nosql.adoc#data.nosql.mongodb[#data.nosql.mongodb] -* xref:reference:data/nosql.adoc#data.nosql.mongodb[#boot-features-mongodb] -* xref:reference:data/nosql.adoc#data.nosql.mongodb.connecting[#data.nosql.mongodb.connecting] +* xref:reference:data/nosql.adoc#data.nosql.ldap.repositories[#features.nosql.ldap.repositories] +* xref:reference:data/nosql.adoc#data.nosql.ldap[#boot-features-ldap] +* xref:reference:data/nosql.adoc#data.nosql.ldap[#data.nosql.ldap] +* xref:reference:data/nosql.adoc#data.nosql.ldap[#features.nosql.ldap] * xref:reference:data/nosql.adoc#data.nosql.mongodb.connecting[#boot-features-connecting-to-mongodb] -* xref:reference:data/nosql.adoc#data.nosql.mongodb.repositories[#data.nosql.mongodb.repositories] +* xref:reference:data/nosql.adoc#data.nosql.mongodb.connecting[#data.nosql.mongodb.connecting] +* xref:reference:data/nosql.adoc#data.nosql.mongodb.connecting[#features.nosql.mongodb.connecting] * xref:reference:data/nosql.adoc#data.nosql.mongodb.repositories[#boot-features-spring-data-mongo-repositories] * xref:reference:data/nosql.adoc#data.nosql.mongodb.repositories[#boot-features-spring-data-mongodb-repositories] -* xref:reference:data/nosql.adoc#data.nosql.mongodb.template[#data.nosql.mongodb.template] +* xref:reference:data/nosql.adoc#data.nosql.mongodb.repositories[#data.nosql.mongodb.repositories] +* xref:reference:data/nosql.adoc#data.nosql.mongodb.repositories[#features.nosql.mongodb.repositories] * xref:reference:data/nosql.adoc#data.nosql.mongodb.template[#boot-features-mongo-template] -* xref:reference:data/nosql.adoc#data.nosql.neo4j[#data.nosql.neo4j] -* xref:reference:data/nosql.adoc#data.nosql.neo4j[#boot-features-neo4j] -* xref:reference:data/nosql.adoc#data.nosql.neo4j.connecting[#data.nosql.neo4j.connecting] +* xref:reference:data/nosql.adoc#data.nosql.mongodb.template[#data.nosql.mongodb.template] +* xref:reference:data/nosql.adoc#data.nosql.mongodb.template[#features.nosql.mongodb.template] +* xref:reference:data/nosql.adoc#data.nosql.mongodb[#boot-features-mongodb] +* xref:reference:data/nosql.adoc#data.nosql.mongodb[#data.nosql.mongodb] +* xref:reference:data/nosql.adoc#data.nosql.mongodb[#features.nosql.mongodb] * xref:reference:data/nosql.adoc#data.nosql.neo4j.connecting[#boot-features-connecting-to-neo4j] -* xref:reference:data/nosql.adoc#data.nosql.neo4j.repositories[#data.nosql.neo4j.repositories] +* xref:reference:data/nosql.adoc#data.nosql.neo4j.connecting[#data.nosql.neo4j.connecting] +* xref:reference:data/nosql.adoc#data.nosql.neo4j.connecting[#features.nosql.neo4j.connecting] * xref:reference:data/nosql.adoc#data.nosql.neo4j.repositories[#boot-features-spring-data-neo4j-repositories] -* xref:reference:data/nosql.adoc#data.nosql.redis[#data.nosql.redis] -* xref:reference:data/nosql.adoc#data.nosql.redis[#boot-features-redis] +* xref:reference:data/nosql.adoc#data.nosql.neo4j.repositories[#data.nosql.neo4j.repositories] +* xref:reference:data/nosql.adoc#data.nosql.neo4j.repositories[#features.nosql.neo4j.repositories] +* xref:reference:data/nosql.adoc#data.nosql.neo4j[#boot-features-neo4j] +* xref:reference:data/nosql.adoc#data.nosql.neo4j[#data.nosql.neo4j] +* xref:reference:data/nosql.adoc#data.nosql.neo4j[#features.nosql.neo4j] * xref:reference:data/nosql.adoc#data.nosql.redis.connecting[#boot-features-connecting-to-redis] * xref:reference:data/nosql.adoc#data.nosql.redis.connecting[#data.nosql.redis.connecting] -* xref:reference:data/sql.adoc#data.sql[#boot-features-sql] -* xref:reference:data/sql.adoc#data.sql[#data.sql] -* xref:reference:data/sql.adoc#data.sql.datasource[#boot-features-configure-datasource] -* xref:reference:data/sql.adoc#data.sql.datasource[#data.sql.datasource] -* xref:reference:data/sql.adoc#data.sql.datasource.configuration[#data.sql.datasource.configuration] +* xref:reference:data/nosql.adoc#data.nosql.redis.connecting[#features.nosql.redis.connecting] +* xref:reference:data/nosql.adoc#data.nosql.redis[#boot-features-redis] +* xref:reference:data/nosql.adoc#data.nosql.redis[#data.nosql.redis] +* xref:reference:data/nosql.adoc#data.nosql.redis[#features.nosql.redis] +* xref:reference:data/nosql.adoc#data.nosql[#boot-features-nosql] +* xref:reference:data/nosql.adoc#data.nosql[#data.nosql] +* xref:reference:data/nosql.adoc#data.nosql[#features.nosql] * xref:reference:data/sql.adoc#data.sql.datasource.configuration[#boot-features-connect-to-production-database-configuration] +* xref:reference:data/sql.adoc#data.sql.datasource.configuration[#data.sql.datasource.configuration] +* xref:reference:data/sql.adoc#data.sql.datasource.configuration[#features.sql.datasource.configuration] * xref:reference:data/sql.adoc#data.sql.datasource.connection-pool[#boot-features-connect-to-production-database-connection-pool] * xref:reference:data/sql.adoc#data.sql.datasource.connection-pool[#data.sql.datasource.connection-pool] -* xref:reference:data/sql.adoc#data.sql.datasource.embedded[#data.sql.datasource.embedded] +* xref:reference:data/sql.adoc#data.sql.datasource.connection-pool[#features.sql.datasource.connection-pool] * xref:reference:data/sql.adoc#data.sql.datasource.embedded[#boot-features-embedded-database-support] +* xref:reference:data/sql.adoc#data.sql.datasource.embedded[#data.sql.datasource.embedded] +* xref:reference:data/sql.adoc#data.sql.datasource.embedded[#features.sql.datasource.embedded] * xref:reference:data/sql.adoc#data.sql.datasource.jndi[#boot-features-connecting-to-a-jndi-datasource] * xref:reference:data/sql.adoc#data.sql.datasource.jndi[#data.sql.datasource.jndi] +* xref:reference:data/sql.adoc#data.sql.datasource.jndi[#features.sql.datasource.jndi] * xref:reference:data/sql.adoc#data.sql.datasource.production[#boot-features-connect-to-production-database] * xref:reference:data/sql.adoc#data.sql.datasource.production[#data.sql.datasource.production] -* xref:reference:data/sql.adoc#data.sql.h2-web-console[#data.sql.h2-web-console] -* xref:reference:data/sql.adoc#data.sql.h2-web-console[#boot-features-sql-h2-console] +* xref:reference:data/sql.adoc#data.sql.datasource.production[#features.sql.datasource.production] +* xref:reference:data/sql.adoc#data.sql.datasource[#boot-features-configure-datasource] +* xref:reference:data/sql.adoc#data.sql.datasource[#data.sql.datasource] +* xref:reference:data/sql.adoc#data.sql.datasource[#features.sql.datasource] * xref:reference:data/sql.adoc#data.sql.h2-web-console.custom-path[#boot-features-sql-h2-console-custom-path] * xref:reference:data/sql.adoc#data.sql.h2-web-console.custom-path[#data.sql.h2-web-console.custom-path] +* xref:reference:data/sql.adoc#data.sql.h2-web-console.custom-path[#features.sql.h2-web-console.custom-path] * xref:reference:data/sql.adoc#data.sql.h2-web-console.spring-security[#data.sql.h2-web-console.spring-security] -* xref:reference:data/sql.adoc#data.sql.jdbc[#data.sql.jdbc] -* xref:reference:data/sql.adoc#data.sql.jdbc[#boot-features-data-jdbc] +* xref:reference:data/sql.adoc#data.sql.h2-web-console[#boot-features-sql-h2-console] +* xref:reference:data/sql.adoc#data.sql.h2-web-console[#data.sql.h2-web-console] +* xref:reference:data/sql.adoc#data.sql.h2-web-console[#features.sql.h2-web-console] * xref:reference:data/sql.adoc#data.sql.jdbc-client[#data.sql.jdbc-client] * xref:reference:data/sql.adoc#data.sql.jdbc-template[#boot-features-using-jdbc-template] * xref:reference:data/sql.adoc#data.sql.jdbc-template[#data.sql.jdbc-template] -* xref:reference:data/sql.adoc#data.sql.jooq[#data.sql.jooq] -* xref:reference:data/sql.adoc#data.sql.jooq[#boot-features-jooq] -* xref:reference:data/sql.adoc#data.sql.jooq.codegen[#data.sql.jooq.codegen] +* xref:reference:data/sql.adoc#data.sql.jdbc-template[#features.sql.jdbc-template] +* xref:reference:data/sql.adoc#data.sql.jdbc[#boot-features-data-jdbc] +* xref:reference:data/sql.adoc#data.sql.jdbc[#data.sql.jdbc] +* xref:reference:data/sql.adoc#data.sql.jdbc[#features.sql.jdbc] * xref:reference:data/sql.adoc#data.sql.jooq.codegen[#boot-features-jooq-codegen] +* xref:reference:data/sql.adoc#data.sql.jooq.codegen[#data.sql.jooq.codegen] +* xref:reference:data/sql.adoc#data.sql.jooq.codegen[#features.sql.jooq.codegen] * xref:reference:data/sql.adoc#data.sql.jooq.customizing[#boot-features-jooq-customizing] * xref:reference:data/sql.adoc#data.sql.jooq.customizing[#data.sql.jooq.customizing] -* xref:reference:data/sql.adoc#data.sql.jooq.dslcontext[#data.sql.jooq.dslcontext] +* xref:reference:data/sql.adoc#data.sql.jooq.customizing[#features.sql.jooq.customizing] * xref:reference:data/sql.adoc#data.sql.jooq.dslcontext[#boot-features-jooq-dslcontext] -* xref:reference:data/sql.adoc#data.sql.jooq.sqldialect[#data.sql.jooq.sqldialect] +* xref:reference:data/sql.adoc#data.sql.jooq.dslcontext[#data.sql.jooq.dslcontext] +* xref:reference:data/sql.adoc#data.sql.jooq.dslcontext[#features.sql.jooq.dslcontext] * xref:reference:data/sql.adoc#data.sql.jooq.sqldialect[#boot-features-jooq-sqldialect] -* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data[#boot-features-jpa-and-spring-data] -* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data[#data.sql.jpa-and-spring-data] +* xref:reference:data/sql.adoc#data.sql.jooq.sqldialect[#data.sql.jooq.sqldialect] +* xref:reference:data/sql.adoc#data.sql.jooq.sqldialect[#features.sql.jooq.sqldialect] +* xref:reference:data/sql.adoc#data.sql.jooq[#boot-features-jooq] +* xref:reference:data/sql.adoc#data.sql.jooq[#data.sql.jooq] +* xref:reference:data/sql.adoc#data.sql.jooq[#features.sql.jooq] * xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.creating-and-dropping[#boot-features-creating-and-dropping-jpa-databases] * xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.creating-and-dropping[#data.sql.jpa-and-spring-data.creating-and-dropping] -* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.entity-classes[#data.sql.jpa-and-spring-data.entity-classes] +* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.creating-and-dropping[#features.sql.jpa-and-spring-data.creating-and-dropping] * xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.entity-classes[#boot-features-entity-classes] +* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.entity-classes[#data.sql.jpa-and-spring-data.entity-classes] +* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.entity-classes[#features.sql.jpa-and-spring-data.entity-classes] * xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.envers-repositories[#data.sql.jpa-and-spring-data.envers-repositories] -* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.open-entity-manager-in-view[#data.sql.jpa-and-spring-data.open-entity-manager-in-view] +* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.envers-repositories[#features.sql.jpa-and-spring-data.envers-repositories] * xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.open-entity-manager-in-view[#boot-features-jpa-in-web-environment] +* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.open-entity-manager-in-view[#data.sql.jpa-and-spring-data.open-entity-manager-in-view] +* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.open-entity-manager-in-view[#features.sql.jpa-and-spring-data.open-entity-manager-in-view] * xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.repositories[#boot-features-spring-data-jpa-repositories] * xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.repositories[#data.sql.jpa-and-spring-data.repositories] -* xref:reference:data/sql.adoc#data.sql.r2dbc[#data.sql.r2dbc] -* xref:reference:data/sql.adoc#data.sql.r2dbc[#boot-features-r2dbc] -* xref:reference:data/sql.adoc#data.sql.r2dbc.embedded[#data.sql.r2dbc.embedded] +* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.repositories[#features.sql.jpa-and-spring-data.repositories] +* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data[#boot-features-jpa-and-spring-data] +* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data[#data.sql.jpa-and-spring-data] +* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data[#features.sql.jpa-and-spring-data] * xref:reference:data/sql.adoc#data.sql.r2dbc.embedded[#boot-features-r2dbc-embedded-database] -* xref:reference:data/sql.adoc#data.sql.r2dbc.repositories[#data.sql.r2dbc.repositories] +* xref:reference:data/sql.adoc#data.sql.r2dbc.embedded[#data.sql.r2dbc.embedded] +* xref:reference:data/sql.adoc#data.sql.r2dbc.embedded[#features.sql.r2dbc.embedded] * xref:reference:data/sql.adoc#data.sql.r2dbc.repositories[#boot-features-spring-data-r2dbc-repositories] -* xref:reference:data/sql.adoc#data.sql.r2dbc.using-database-client[#data.sql.r2dbc.using-database-client] +* xref:reference:data/sql.adoc#data.sql.r2dbc.repositories[#data.sql.r2dbc.repositories] +* xref:reference:data/sql.adoc#data.sql.r2dbc.repositories[#features.sql.r2dbc.repositories] * xref:reference:data/sql.adoc#data.sql.r2dbc.using-database-client[#boot-features-r2dbc-using-database-client] -* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud[#deployment.cloud] -* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws[#deployment.cloud.aws] -* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws.beanstalk[#deployment.cloud.aws.beanstalk] -* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws.beanstalk.java-se-platform[#deployment.cloud.aws.beanstalk.java-se-platform] -* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws.beanstalk.tomcat-platform[#deployment.cloud.aws.beanstalk.tomcat-platform] -* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws.summary[#deployment.cloud.aws.summary] -* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.azure[#deployment.cloud.azure] -* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.boxfuse[#deployment.cloud.boxfuse] -* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.cloud-foundry[#deployment.cloud.cloud-foundry] -* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.cloud-foundry.binding-to-services[#deployment.cloud.cloud-foundry.binding-to-services] -* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.google[#deployment.cloud.google] -* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.heroku[#deployment.cloud.heroku] -* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.kubernetes[#deployment.cloud.kubernetes] -* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.kubernetes.container-lifecycle[#deployment.cloud.kubernetes.container-lifecycle] -* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.openshift[#deployment.cloud.openshift] -* xref:reference:packaging/efficient.adoc#packaging.efficient[#deployment.efficient] -* xref:reference:packaging/aot.adoc#packaging.aot[#deployment.efficient.aot] -* xref:reference:packaging/checkpoint-restore.adoc#packaging.checkpoint-restore[#deployment.efficient.checkpoint-restore] -* xref:reference:packaging/efficient.adoc#packaging.efficient.unpacking[#containers-deployment] -* xref:reference:packaging/efficient.adoc#packaging.efficient.unpacking[#deployment.containers] -* xref:reference:packaging/efficient.adoc#packaging.efficient.unpacking[#deployment.efficient.unpacking] -* xref:how-to:deployment/index.adoc#howto.deployment[#deployment] -* xref:how-to:deployment/installing.adoc#howto.deployment.installing[#deployment-install-supported-operating-systems] -* xref:how-to:deployment/installing.adoc#howto.deployment.installing[#deployment.installing] -* xref:how-to:deployment/installing.adoc#howto.deployment.installing[#deployment-service] -* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d[#deployment.installing.init-d] -* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d[#deployment-initd-service] -* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d.script-customization[#deployment-script-customization] -* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d.script-customization[#deployment.installing.init-d.script-customization] -* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d.script-customization.when-running[#deployment-script-customization-when-it-runs] -* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d.script-customization.when-running[#deployment.installing.init-d.script-customization.when-running] -* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d.script-customization.when-running.conf-file[#deployment.installing.init-d.script-customization.when-running.conf-file] -* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d.script-customization.when-written[#deployment-script-customization-when-it-written] -* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d.script-customization.when-written[#deployment.installing.init-d.script-customization.when-written] -* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d.securing[#deployment.installing.init-d.securing] -* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d.securing[#deployment-initd-service-securing] -* xref:how-to:deployment/installing.adoc#howto.deployment.installing.system-d[#deployment-systemd-service] -* xref:how-to:deployment/installing.adoc#howto.deployment.installing.system-d[#deployment.installing.system-d] -* xref:how-to:deployment/installing.adoc#howto.deployment.installing.windows-services[#deployment.installing.windows-services] +* xref:reference:data/sql.adoc#data.sql.r2dbc.using-database-client[#data.sql.r2dbc.using-database-client] +* xref:reference:data/sql.adoc#data.sql.r2dbc.using-database-client[#features.sql.r2dbc.using-database-client] +* xref:reference:data/sql.adoc#data.sql.r2dbc[#boot-features-r2dbc] +* xref:reference:data/sql.adoc#data.sql.r2dbc[#data.sql.r2dbc] +* xref:reference:data/sql.adoc#data.sql.r2dbc[#features.sql.r2dbc] +* xref:reference:data/sql.adoc#data.sql[#boot-features-sql] +* xref:reference:data/sql.adoc#data.sql[#data.sql] +* xref:reference:data/sql.adoc#data.sql[#features.sql] * xref:reference:features/aop.adoc#features.aop[#features.aop] -* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration[#features.developing-auto-configuration] -* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations[#features.developing-auto-configuration.condition-annotations] +* xref:reference:features/dev-services.adoc#features.dev-services.docker-compose.custom-images[#features.docker-compose.custom-images] +* xref:reference:features/dev-services.adoc#features.dev-services.docker-compose.lifecycle[#features.docker-compose.lifecycle] +* xref:reference:features/dev-services.adoc#features.dev-services.docker-compose.prerequisites[#features.docker-compose.prerequisites] +* xref:reference:features/dev-services.adoc#features.dev-services.docker-compose.profiles[#features.docker-compose.profiles] +* xref:reference:features/dev-services.adoc#features.dev-services.docker-compose.readiness[#features.docker-compose.readiness] +* xref:reference:features/dev-services.adoc#features.dev-services.docker-compose.service-connections[#features.docker-compose.service-connections] +* xref:reference:features/dev-services.adoc#features.dev-services.docker-compose.skipping[#features.docker-compose.skipping] +* xref:reference:features/dev-services.adoc#features.dev-services.docker-compose.specific-file[#features.docker-compose.specific-file] +* xref:reference:features/dev-services.adoc#features.dev-services.docker-compose[#features.docker-compose] +* xref:reference:features/dev-services.adoc#features.dev-services.testcontainers.at-development-time.devtools[#features.testcontainers.at-development-time.devtools] +* xref:reference:features/dev-services.adoc#features.dev-services.testcontainers.at-development-time.devtools[#features.testing.testcontainers.at-development-time.devtools] +* xref:reference:features/dev-services.adoc#features.dev-services.testcontainers.at-development-time.dynamic-properties[#features.testcontainers.at-development-time.dynamic-properties] +* xref:reference:features/dev-services.adoc#features.dev-services.testcontainers.at-development-time.dynamic-properties[#features.testing.testcontainers.at-development-time.dynamic-properties] +* xref:reference:features/dev-services.adoc#features.dev-services.testcontainers.at-development-time.importing-container-declarations[#features.testcontainers.at-development-time.importing-container-declarations] +* xref:reference:features/dev-services.adoc#features.dev-services.testcontainers.at-development-time.importing-container-declarations[#features.testing.testcontainers.at-development-time.importing-container-declarations] +* xref:reference:features/dev-services.adoc#features.dev-services.testcontainers.at-development-time[#features.testcontainers.at-development-time] +* xref:reference:features/dev-services.adoc#features.dev-services.testcontainers.at-development-time[#features.testing.testcontainers.at-development-time] +* xref:reference:features/dev-services.adoc#features.dev-services.testcontainers[#features.testcontainers] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.bean-conditions[#boot-features-bean-conditions] * xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.bean-conditions[#features.developing-auto-configuration.condition-annotations.bean-conditions] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.class-conditions[#boot-features-class-conditions] * xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.class-conditions[#features.developing-auto-configuration.condition-annotations.class-conditions] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.property-conditions[#boot-features-property-conditions] * xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.property-conditions[#features.developing-auto-configuration.condition-annotations.property-conditions] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.resource-conditions[#boot-features-resource-conditions] * xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.resource-conditions[#features.developing-auto-configuration.condition-annotations.resource-conditions] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.spel-conditions[#boot-features-spel-conditions] * xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.spel-conditions[#features.developing-auto-configuration.condition-annotations.spel-conditions] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.web-application-conditions[#boot-features-web-application-conditions] * xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.web-application-conditions[#features.developing-auto-configuration.condition-annotations.web-application-conditions] -* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.custom-starter[#features.developing-auto-configuration.custom-starter] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations[#boot-features-condition-annotations] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations[#features.developing-auto-configuration.condition-annotations] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.custom-starter.autoconfigure-module[#boot-features-custom-starter-module-autoconfigure] * xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.custom-starter.autoconfigure-module[#features.developing-auto-configuration.custom-starter.autoconfigure-module] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.custom-starter.configuration-keys[#boot-features-custom-starter-configuration-keys] * xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.custom-starter.configuration-keys[#features.developing-auto-configuration.custom-starter.configuration-keys] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.custom-starter.naming[#boot-features-custom-starter-naming] * xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.custom-starter.naming[#features.developing-auto-configuration.custom-starter.naming] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.custom-starter.starter-module[#boot-features-custom-starter-module-starter] * xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.custom-starter.starter-module[#features.developing-auto-configuration.custom-starter.starter-module] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.custom-starter[#boot-features-custom-starter] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.custom-starter[#features.developing-auto-configuration.custom-starter] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.locating-auto-configuration-candidates[#boot-features-locating-auto-configuration-candidates] * xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.locating-auto-configuration-candidates[#features.developing-auto-configuration.locating-auto-configuration-candidates] -* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.testing[#features.developing-auto-configuration.testing] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.testing.overriding-classpath[#boot-features-test-autoconfig-overriding-classpath] * xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.testing.overriding-classpath[#features.developing-auto-configuration.testing.overriding-classpath] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.testing.simulating-a-web-context[#boot-features-test-autoconfig-simulating-web-context] * xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.testing.simulating-a-web-context[#features.developing-auto-configuration.testing.simulating-a-web-context] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.testing[#boot-features-test-autoconfig] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.testing[#features.developing-auto-configuration.testing] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.understanding-auto-configured-beans[#boot-features-understanding-auto-configured-beans] * xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.understanding-auto-configured-beans[#features.developing-auto-configuration.understanding-auto-configured-beans] -* xref:reference:features/dev-services.adoc#features.dev-services.docker-compose[#features.docker-compose] -* xref:reference:features/dev-services.adoc#features.dev-services.docker-compose.custom-images[#features.docker-compose.custom-images] -* xref:reference:features/dev-services.adoc#features.dev-services.docker-compose.lifecycle[#features.docker-compose.lifecycle] -* xref:reference:features/dev-services.adoc#features.dev-services.docker-compose.prerequisites[#features.docker-compose.prerequisites] -* xref:reference:features/dev-services.adoc#features.dev-services.docker-compose.profiles[#features.docker-compose.profiles] -* xref:reference:features/dev-services.adoc#features.dev-services.docker-compose.readiness[#features.docker-compose.readiness] -* xref:reference:features/dev-services.adoc#features.dev-services.docker-compose.service-connections[#features.docker-compose.service-connections] -* xref:reference:features/dev-services.adoc#features.dev-services.docker-compose.skipping[#features.docker-compose.skipping] -* xref:reference:features/dev-services.adoc#features.dev-services.docker-compose.specific-file[#features.docker-compose.specific-file] -* xref:reference:features/external-config.adoc#features.external-config[#features.external-config] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration[#boot-features-developing-auto-configuration] +* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration[#features.developing-auto-configuration] +* xref:reference:features/external-config.adoc#features.external-config.application-json[#boot-features-external-config-application-json] * xref:reference:features/external-config.adoc#features.external-config.application-json[#features.external-config.application-json] +* xref:reference:features/external-config.adoc#features.external-config.command-line-args[#boot-features-external-config-command-line-args] * xref:reference:features/external-config.adoc#features.external-config.command-line-args[#features.external-config.command-line-args] +* xref:reference:features/external-config.adoc#features.external-config.encrypting[#boot-features-encrypting-properties] * xref:reference:features/external-config.adoc#features.external-config.encrypting[#features.external-config.encrypting] -* xref:reference:features/external-config.adoc#features.external-config.files[#features.external-config.files] +* xref:reference:features/external-config.adoc#features.external-config.files.activation-properties[#boot-features-external-config-file-activation-properties] * xref:reference:features/external-config.adoc#features.external-config.files.activation-properties[#features.external-config.files.activation-properties] +* xref:reference:features/external-config.adoc#features.external-config.files.configtree[#boot-features-external-config-files-configtree] * xref:reference:features/external-config.adoc#features.external-config.files.configtree[#features.external-config.files.configtree] -* xref:reference:features/external-config.adoc#features.external-config.files.importing[#features.external-config.files.importing] +* xref:reference:features/external-config.adoc#features.external-config.files.importing-extensionless[#boot-features-external-config-files-importing-extensionless] +* xref:reference:features/external-config.adoc#features.external-config.files.importing-extensionless[#features.external-config.file.importing-extensionless] * xref:reference:features/external-config.adoc#features.external-config.files.importing-extensionless[#features.external-config.files.importing-extensionless] +* xref:reference:features/external-config.adoc#features.external-config.files.importing[#boot-features-external-config-files-importing] +* xref:reference:features/external-config.adoc#features.external-config.files.importing[#features.external-config.files.importing] * xref:reference:features/external-config.adoc#features.external-config.files.location-groups[#features.external-config.files.location-groups] +* xref:reference:features/external-config.adoc#features.external-config.files.multi-document[#boot-features-external-config-files-multi-document] * xref:reference:features/external-config.adoc#features.external-config.files.multi-document[#features.external-config.files.multi-document] +* xref:reference:features/external-config.adoc#features.external-config.files.optional-prefix[#boot-features-external-config-optional-prefix] * xref:reference:features/external-config.adoc#features.external-config.files.optional-prefix[#features.external-config.files.optional-prefix] +* xref:reference:features/external-config.adoc#features.external-config.files.profile-specific[#boot-features-external-config-files-profile-specific] * xref:reference:features/external-config.adoc#features.external-config.files.profile-specific[#features.external-config.files.profile-specific] +* xref:reference:features/external-config.adoc#features.external-config.files.property-placeholders[#boot-features-external-config-placeholders-in-properties] * xref:reference:features/external-config.adoc#features.external-config.files.property-placeholders[#features.external-config.files.property-placeholders] +* xref:reference:features/external-config.adoc#features.external-config.files.wildcard-locations[#boot-features-external-config-files-wildcards] * xref:reference:features/external-config.adoc#features.external-config.files.wildcard-locations[#features.external-config.files.wildcard-locations] +* xref:reference:features/external-config.adoc#features.external-config.files[#boot-features-external-config-files] +* xref:reference:features/external-config.adoc#features.external-config.files[#features.external-config.files] +* xref:reference:features/external-config.adoc#features.external-config.random-values[#boot-features-external-config-random-values] * xref:reference:features/external-config.adoc#features.external-config.random-values[#features.external-config.random-values] +* xref:reference:features/external-config.adoc#features.external-config.system-environment[#boot-features-external-config-system-environment] * xref:reference:features/external-config.adoc#features.external-config.system-environment[#features.external-config.system-environment] -* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties[#features.external-config.typesafe-configuration-properties] +* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.constructor-binding[#boot-features-external-config-constructor-binding] * xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.constructor-binding[#features.external-config.typesafe-configuration-properties.constructor-binding] -* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.conversion[#features.external-config.typesafe-configuration-properties.conversion] +* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.conversion.data-sizes[#boot-features-external-config-conversion-datasize] * xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.conversion.data-sizes[#features.external-config.typesafe-configuration-properties.conversion.data-sizes] +* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.conversion.durations[#boot-features-external-config-conversion-duration] * xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.conversion.durations[#features.external-config.typesafe-configuration-properties.conversion.durations] +* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.conversion.periods[#boot-features-external-config-conversion-period] * xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.conversion.periods[#features.external-config.typesafe-configuration-properties.conversion.periods] +* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.conversion[#boot-features-external-config-conversion] +* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.conversion[#features.external-config.typesafe-configuration-properties.conversion] +* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.enabling-annotated-types[#boot-features-external-config-enabling] * xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.enabling-annotated-types[#features.external-config.typesafe-configuration-properties.enabling-annotated-types] +* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.java-bean-binding[#boot-features-external-config-java-bean-binding] * xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.java-bean-binding[#features.external-config.typesafe-configuration-properties.java-bean-binding] +* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.merging-complex-types[#boot-features-external-config-complex-type-merge] * xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.merging-complex-types[#features.external-config.typesafe-configuration-properties.merging-complex-types] -* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.relaxed-binding[#features.external-config.typesafe-configuration-properties.relaxed-binding] * xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.relaxed-binding.caching[#features.external-config.typesafe-configuration-properties.relaxed-binding.caching] +* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.relaxed-binding.environment-variables[#boot-features-external-config-relaxed-binding-from-environment-variables] * xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.relaxed-binding.environment-variables[#features.external-config.typesafe-configuration-properties.relaxed-binding.environment-variables] +* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.relaxed-binding.maps[#boot-features-external-config-relaxed-binding-maps] * xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.relaxed-binding.maps[#features.external-config.typesafe-configuration-properties.relaxed-binding.maps] +* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.relaxed-binding[#boot-features-external-config-relaxed-binding] +* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.relaxed-binding[#features.external-config.typesafe-configuration-properties.relaxed-binding] +* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.third-party-configuration[#boot-features-external-config-3rd-party-configuration] * xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.third-party-configuration[#features.external-config.typesafe-configuration-properties.third-party-configuration] +* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.using-annotated-types[#boot-features-external-config-using] * xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.using-annotated-types[#features.external-config.typesafe-configuration-properties.using-annotated-types] +* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.validation[#boot-features-external-config-validation] * xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.validation[#features.external-config.typesafe-configuration-properties.validation] -* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.vs-value-annotation[#features.external-config.typesafe-configuration-properties.vs-value-annotation] * xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.vs-value-annotation.note[#features.external-config.typesafe-configuration-properties.vs-value-annotation.note] -* xref:reference:features/external-config.adoc#features.external-config.yaml[#features.external-config.yaml] +* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.vs-value-annotation[#boot-features-external-config-vs-value] +* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.vs-value-annotation[#features.external-config.typesafe-configuration-properties.vs-value-annotation] +* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties[#boot-features-external-config-typesafe-configuration-properties] +* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties[#features.external-config.typesafe-configuration-properties] +* xref:reference:features/external-config.adoc#features.external-config.yaml.directly-loading[#boot-features-external-config-loading-yaml] * xref:reference:features/external-config.adoc#features.external-config.yaml.directly-loading[#features.external-config.yaml.directly-loading] +* xref:reference:features/external-config.adoc#features.external-config.yaml.mapping-to-properties[#boot-features-external-config-yaml-to-properties] * xref:reference:features/external-config.adoc#features.external-config.yaml.mapping-to-properties[#features.external-config.yaml.mapping-to-properties] +* xref:reference:features/external-config.adoc#features.external-config.yaml[#boot-features-external-config-yaml] +* xref:reference:features/external-config.adoc#features.external-config.yaml[#features.external-config.yaml] +* xref:reference:features/external-config.adoc#features.external-config[#boot-features-external-config] +* xref:reference:features/external-config.adoc#features.external-config[#features.external-config] +* xref:reference:features/index.adoc#features[#boot-features] * xref:reference:features/index.adoc#features[#features] +* xref:reference:features/index.adoc[#features] +* xref:reference:features/index.adoc[features] +* xref:reference:features/internationalization.adoc#features.internationalization[#boot-features-internationalization] * xref:reference:features/internationalization.adoc#features.internationalization[#features.internationalization] -* xref:reference:features/json.adoc#features.json[#features.json] +* xref:reference:features/json.adoc#features.json.gson[#boot-features-json-gson] * xref:reference:features/json.adoc#features.json.gson[#features.json.gson] -* xref:reference:features/json.adoc#features.json.jackson[#features.json.jackson] * xref:reference:features/json.adoc#features.json.jackson.custom-serializers-and-deserializers[#boot-features-json-components] * xref:reference:features/json.adoc#features.json.jackson.custom-serializers-and-deserializers[#features.developing-web-applications.spring-mvc.json] * xref:reference:features/json.adoc#features.json.jackson.custom-serializers-and-deserializers[#features.json.jackson.custom-serializers-and-deserializers] +* xref:reference:features/json.adoc#features.json.jackson.custom-serializers-and-deserializers[#web.servlet.spring-mvc.json] * xref:reference:features/json.adoc#features.json.jackson.mixins[#features.json.jackson.mixins] +* xref:reference:features/json.adoc#features.json.jackson[#boot-features-json-jackson] +* xref:reference:features/json.adoc#features.json.jackson[#features.json.jackson] +* xref:reference:features/json.adoc#features.json.json-b[#boot-features-json-json-b] * xref:reference:features/json.adoc#features.json.json-b[#features.json.json-b] -* xref:reference:features/kotlin.adoc#features.kotlin[#features.kotlin] -* xref:reference:features/kotlin.adoc#features.kotlin.api[#features.kotlin.api] +* xref:reference:features/json.adoc#features.json[#boot-features-json] +* xref:reference:features/json.adoc#features.json[#features.json] +* xref:reference:features/kotlin.adoc#features.kotlin.api.extensions[#boot-features-kotlin-api-extensions] * xref:reference:features/kotlin.adoc#features.kotlin.api.extensions[#features.kotlin.api.extensions] +* xref:reference:features/kotlin.adoc#features.kotlin.api.run-application[#boot-features-kotlin-api-runapplication] * xref:reference:features/kotlin.adoc#features.kotlin.api.run-application[#features.kotlin.api.run-application] +* xref:reference:features/kotlin.adoc#features.kotlin.api[#boot-features-kotlin-api] +* xref:reference:features/kotlin.adoc#features.kotlin.api[#features.kotlin.api] +* xref:reference:features/kotlin.adoc#features.kotlin.configuration-properties[#boot-features-kotlin-configuration-properties] * xref:reference:features/kotlin.adoc#features.kotlin.configuration-properties[#features.kotlin.configuration-properties] +* xref:reference:features/kotlin.adoc#features.kotlin.dependency-management[#boot-features-kotlin-dependency-management] * xref:reference:features/kotlin.adoc#features.kotlin.dependency-management[#features.kotlin.dependency-management] +* xref:reference:features/kotlin.adoc#features.kotlin.null-safety[#boot-features-kotlin-null-safety] * xref:reference:features/kotlin.adoc#features.kotlin.null-safety[#features.kotlin.null-safety] +* xref:reference:features/kotlin.adoc#features.kotlin.requirements[#boot-features-kotlin-requirements] * xref:reference:features/kotlin.adoc#features.kotlin.requirements[#features.kotlin.requirements] -* xref:reference:features/kotlin.adoc#features.kotlin.resources[#features.kotlin.resources] +* xref:reference:features/kotlin.adoc#features.kotlin.resources.examples[#boot-features-kotlin-resources-examples] * xref:reference:features/kotlin.adoc#features.kotlin.resources.examples[#features.kotlin.resources.examples] +* xref:reference:features/kotlin.adoc#features.kotlin.resources.further-reading[#boot-features-kotlin-resources-further-reading] * xref:reference:features/kotlin.adoc#features.kotlin.resources.further-reading[#features.kotlin.resources.further-reading] +* xref:reference:features/kotlin.adoc#features.kotlin.resources[#boot-features-kotlin-resources] +* xref:reference:features/kotlin.adoc#features.kotlin.resources[#features.kotlin.resources] +* xref:reference:features/kotlin.adoc#features.kotlin.testing[#boot-features-kotlin-testing] * xref:reference:features/kotlin.adoc#features.kotlin.testing[#features.kotlin.testing] -* xref:reference:features/logging.adoc#features.logging[#features.logging] -* xref:reference:features/logging.adoc#features.logging.console-output[#features.logging.console-output] +* xref:reference:features/kotlin.adoc#features.kotlin[#boot-features-kotlin] +* xref:reference:features/kotlin.adoc#features.kotlin[#features.kotlin] +* xref:reference:features/logging.adoc#features.logging.console-output.color-coded[#boot-features-logging-color-coded-output] * xref:reference:features/logging.adoc#features.logging.console-output.color-coded[#features.logging.console-output.color-coded] +* xref:reference:features/logging.adoc#features.logging.console-output[#boot-features-logging-console-output] +* xref:reference:features/logging.adoc#features.logging.console-output[#features.logging.console-output] +* xref:reference:features/logging.adoc#features.logging.custom-log-configuration[#boot-features-custom-log-configuration] * xref:reference:features/logging.adoc#features.logging.custom-log-configuration[#features.logging.custom-log-configuration] +* xref:reference:features/logging.adoc#features.logging.file-output[#boot-features-logging-file-output] * xref:reference:features/logging.adoc#features.logging.file-output[#features.logging.file-output] +* xref:reference:features/logging.adoc#features.logging.file-rotation[#boot-features-logging-file-rotation] * xref:reference:features/logging.adoc#features.logging.file-rotation[#features.logging.file-rotation] +* xref:reference:features/logging.adoc#features.logging.log-format[#boot-features-logging-format] * xref:reference:features/logging.adoc#features.logging.log-format[#features.logging.log-format] +* xref:reference:features/logging.adoc#features.logging.log-groups[#boot-features-custom-log-groups] * xref:reference:features/logging.adoc#features.logging.log-groups[#features.logging.log-groups] +* xref:reference:features/logging.adoc#features.logging.log-levels[#boot-features-custom-log-levels] * xref:reference:features/logging.adoc#features.logging.log-levels[#features.logging.log-levels] -* xref:reference:features/logging.adoc#features.logging.log4j2-extensions[#features.logging.log4j2-extensions] * xref:reference:features/logging.adoc#features.logging.log4j2-extensions.environment-properties-lookup[#features.logging.log4j2-extensions.environment-properties-lookup] * xref:reference:features/logging.adoc#features.logging.log4j2-extensions.environment-property-source[#features.logging.log4j2-extensions.environment-property-source] * xref:reference:features/logging.adoc#features.logging.log4j2-extensions.profile-specific[#features.logging.log4j2-extensions.profile-specific] -* xref:reference:features/logging.adoc#features.logging.logback-extensions[#features.logging.logback-extensions] +* xref:reference:features/logging.adoc#features.logging.log4j2-extensions[#features.logging.log4j2-extensions] +* xref:reference:features/logging.adoc#features.logging.logback-extensions.environment-properties[#boot-features-logback-environment-properties] * xref:reference:features/logging.adoc#features.logging.logback-extensions.environment-properties[#features.logging.logback-extensions.environment-properties] +* xref:reference:features/logging.adoc#features.logging.logback-extensions.profile-specific[#boot-features-logback-extensions-profile-specific] * xref:reference:features/logging.adoc#features.logging.logback-extensions.profile-specific[#features.logging.logback-extensions.profile-specific] +* xref:reference:features/logging.adoc#features.logging.logback-extensions[#boot-features-logback-extensions] +* xref:reference:features/logging.adoc#features.logging.logback-extensions[#features.logging.logback-extensions] +* xref:reference:features/logging.adoc#features.logging.shutdown-hook[#boot-features-log-shutdown-hook] * xref:reference:features/logging.adoc#features.logging.shutdown-hook[#features.logging.shutdown-hook] -* xref:reference:features/profiles.adoc#features.profiles[#features.profiles] +* xref:reference:features/logging.adoc#features.logging[#boot-features-logging] +* xref:reference:features/logging.adoc#features.logging[#features.logging] +* xref:reference:features/profiles.adoc#features.profiles.adding-active-profiles[#boot-features-adding-active-profiles] * xref:reference:features/profiles.adoc#features.profiles.adding-active-profiles[#features.profiles.adding-active-profiles] +* xref:reference:features/profiles.adoc#features.profiles.groups[#boot-features-profiles-groups] * xref:reference:features/profiles.adoc#features.profiles.groups[#features.profiles.groups] +* xref:reference:features/profiles.adoc#features.profiles.profile-specific-configuration-files[#boot-features-profile-specific-configuration] * xref:reference:features/profiles.adoc#features.profiles.profile-specific-configuration-files[#features.profiles.profile-specific-configuration-files] +* xref:reference:features/profiles.adoc#features.profiles.programmatically-setting-profiles[#boot-features-programmatically-setting-profiles] * xref:reference:features/profiles.adoc#features.profiles.programmatically-setting-profiles[#features.profiles.programmatically-setting-profiles] -* xref:reference:features/spring-application.adoc#features.spring-application[#features.spring-application] +* xref:reference:features/profiles.adoc#features.profiles[#boot-features-profiles] +* xref:reference:features/profiles.adoc#features.profiles[#features.profiles] +* xref:reference:features/spring-application.adoc#features.spring-application.admin[#boot-features-application-admin] * xref:reference:features/spring-application.adoc#features.spring-application.admin[#features.spring-application.admin] +* xref:reference:features/spring-application.adoc#features.spring-application.application-arguments[#boot-features-application-arguments] * xref:reference:features/spring-application.adoc#features.spring-application.application-arguments[#features.spring-application.application-arguments] -* xref:reference:features/spring-application.adoc#features.spring-application.application-availability[#features.spring-application.application-availability] +* xref:reference:features/spring-application.adoc#features.spring-application.application-availability.liveness[#boot-features-application-availability-liveness-state] * xref:reference:features/spring-application.adoc#features.spring-application.application-availability.liveness[#features.spring-application.application-availability.liveness] +* xref:reference:features/spring-application.adoc#features.spring-application.application-availability.managing[#boot-features-application-availability-managing] * xref:reference:features/spring-application.adoc#features.spring-application.application-availability.managing[#features.spring-application.application-availability.managing] +* xref:reference:features/spring-application.adoc#features.spring-application.application-availability.readiness[#boot-features-application-availability-readiness-state] * xref:reference:features/spring-application.adoc#features.spring-application.application-availability.readiness[#features.spring-application.application-availability.readiness] +* xref:reference:features/spring-application.adoc#features.spring-application.application-availability[#boot-features-application-availability] +* xref:reference:features/spring-application.adoc#features.spring-application.application-availability[#features.spring-application.application-availability] +* xref:reference:features/spring-application.adoc#features.spring-application.application-events-and-listeners[#boot-features-application-events-and-listeners] * xref:reference:features/spring-application.adoc#features.spring-application.application-events-and-listeners[#features.spring-application.application-events-and-listeners] +* xref:reference:features/spring-application.adoc#features.spring-application.application-exit[#boot-features-application-exit] * xref:reference:features/spring-application.adoc#features.spring-application.application-exit[#features.spring-application.application-exit] +* xref:reference:features/spring-application.adoc#features.spring-application.banner[#boot-features-banner] * xref:reference:features/spring-application.adoc#features.spring-application.banner[#features.spring-application.banner] +* xref:reference:features/spring-application.adoc#features.spring-application.command-line-runner[#boot-features-command-line-runner] * xref:reference:features/spring-application.adoc#features.spring-application.command-line-runner[#features.spring-application.command-line-runner] +* xref:reference:features/spring-application.adoc#features.spring-application.customizing-spring-application[#boot-features-customizing-spring-application] * xref:reference:features/spring-application.adoc#features.spring-application.customizing-spring-application[#features.spring-application.customizing-spring-application] +* xref:reference:features/spring-application.adoc#features.spring-application.fluent-builder-api[#boot-features-fluent-builder-api] * xref:reference:features/spring-application.adoc#features.spring-application.fluent-builder-api[#features.spring-application.fluent-builder-api] +* xref:reference:features/spring-application.adoc#features.spring-application.lazy-initialization[#boot-features-lazy-initialization] * xref:reference:features/spring-application.adoc#features.spring-application.lazy-initialization[#features.spring-application.lazy-initialization] +* xref:reference:features/spring-application.adoc#features.spring-application.startup-failure[#boot-features-startup-failure] * xref:reference:features/spring-application.adoc#features.spring-application.startup-failure[#features.spring-application.startup-failure] +* xref:reference:features/spring-application.adoc#features.spring-application.startup-tracking[#boot-features-application-startup-tracking] * xref:reference:features/spring-application.adoc#features.spring-application.startup-tracking[#features.spring-application.startup-tracking] * xref:reference:features/spring-application.adoc#features.spring-application.virtual-threads[#features.spring-application.virtual-threads] +* xref:reference:features/spring-application.adoc#features.spring-application.web-environment[#boot-features-web-environment] * xref:reference:features/spring-application.adoc#features.spring-application.web-environment[#features.spring-application.web-environment] -* xref:reference:features/ssl.adoc#features.ssl[#features.ssl] +* xref:reference:features/spring-application.adoc#features.spring-application[#boot-features-spring-application] +* xref:reference:features/spring-application.adoc#features.spring-application[#features.spring-application] * xref:reference:features/ssl.adoc#features.ssl.applying[#features.ssl.applying] * xref:reference:features/ssl.adoc#features.ssl.bundles[#features.ssl.bundles] * xref:reference:features/ssl.adoc#features.ssl.jks[#features.ssl.jks] * xref:reference:features/ssl.adoc#features.ssl.pem[#features.ssl.pem] * xref:reference:features/ssl.adoc#features.ssl.reloading[#features.ssl.reloading] +* xref:reference:features/ssl.adoc#features.ssl[#features.ssl] +* xref:reference:features/task-execution-and-scheduling.adoc#features.task-execution-and-scheduling[#boot-features-task-execution-scheduling] * xref:reference:features/task-execution-and-scheduling.adoc#features.task-execution-and-scheduling[#features.task-execution-and-scheduling] -* xref:reference:features/dev-services.adoc#features.dev-services.testcontainers[#features.testcontainers] -* xref:reference:features/dev-services.adoc#features.dev-services.testcontainers.at-development-time[#features.testcontainers.at-development-time] -* xref:reference:features/dev-services.adoc#features.dev-services.testcontainers.at-development-time.devtools[#features.testcontainers.at-development-time.devtools] -* xref:reference:features/dev-services.adoc#features.dev-services.testcontainers.at-development-time.dynamic-properties[#features.testcontainers.at-development-time.dynamic-properties] -* xref:reference:features/dev-services.adoc#features.dev-services.testcontainers.at-development-time.importing-container-declarations[#features.testcontainers.at-development-time.importing-container-declarations] -* xref:reference:testing/index.adoc#testing[#features.testing] -* xref:reference:testing/spring-applications.adoc#testing.spring-applications[#features.testing.spring-applications] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications[#features.testing.spring-boot-applications] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.additional-autoconfiguration-and-slicing[#features.testing.spring-boot-applications.additional-autoconfiguration-and-slicing] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-jdbc[#features.testing.spring-boot-applications.autoconfigured-jdbc] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-jooq[#features.testing.spring-boot-applications.autoconfigured-jooq] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-rest-client[#features.testing.spring-boot-applications.autoconfigured-rest-client] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-cassandra[#features.testing.spring-boot-applications.autoconfigured-spring-data-cassandra] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-couchbase[#features.testing.spring-boot-applications.autoconfigured-spring-data-couchbase] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-elasticsearch[#features.testing.spring-boot-applications.autoconfigured-spring-data-elasticsearch] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-jdbc[#features.testing.spring-boot-applications.autoconfigured-spring-data-jdbc] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-jpa[#features.testing.spring-boot-applications.autoconfigured-spring-data-jpa] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-ldap[#features.testing.spring-boot-applications.autoconfigured-spring-data-ldap] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-mongodb[#features.testing.spring-boot-applications.autoconfigured-spring-data-mongodb] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-neo4j[#features.testing.spring-boot-applications.autoconfigured-spring-data-neo4j] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-r2dbc[#features.testing.spring-boot-applications.autoconfigured-spring-data-r2dbc] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-redis[#features.testing.spring-boot-applications.autoconfigured-spring-data-redis] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-restdocs[#features.testing.spring-boot-applications.autoconfigured-spring-restdocs] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-restdocs.with-mock-mvc[#features.testing.spring-boot-applications.autoconfigured-spring-restdocs.with-mock-mvc] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-restdocs.with-rest-assured[#features.testing.spring-boot-applications.autoconfigured-spring-restdocs.with-rest-assured] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-restdocs.with-web-test-client[#features.testing.spring-boot-applications.autoconfigured-spring-restdocs.with-web-test-client] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-tests[#features.testing.spring-boot-applications.autoconfigured-tests] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-webservices[#features.testing.spring-boot-applications.autoconfigured-webservices] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-webservices.client[#features.testing.spring-boot-applications.autoconfigured-webservices.client] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-webservices.server[#features.testing.spring-boot-applications.autoconfigured-webservices.server] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.customizing-web-test-client[#features.testing.spring-boot-applications.customizing-web-test-client] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.detecting-configuration[#features.testing.spring-boot-applications.detecting-configuration] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.detecting-web-app-type[#features.testing.spring-boot-applications.detecting-web-app-type] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.excluding-configuration[#features.testing.spring-boot-applications.excluding-configuration] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.jmx[#features.testing.spring-boot-applications.jmx] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.json-tests[#features.testing.spring-boot-applications.json-tests] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.metrics[#features.testing.spring-boot-applications.metrics] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.mocking-beans[#features.testing.spring-boot-applications.mocking-beans] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.observations[#features.testing.spring-boot-applications.observations] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.spock[#features.testing.spring-boot-applications.spock] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.spring-graphql-tests[#features.testing.spring-boot-applications.spring-graphql-tests] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.spring-mvc-tests[#features.testing.spring-boot-applications.spring-mvc-tests] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.spring-webflux-tests[#features.testing.spring-boot-applications.spring-webflux-tests] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.tracing[#features.testing.spring-boot-applications.tracing] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.user-configuration-and-slicing[#features.testing.spring-boot-applications.user-configuration-and-slicing] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.using-application-arguments[#features.testing.spring-boot-applications.using-application-arguments] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.using-main[#features.testing.spring-boot-applications.using-main] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.with-mock-environment[#features.testing.spring-boot-applications.with-mock-environment] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.with-running-server[#features.testing.spring-boot-applications.with-running-server] -* xref:reference:testing/test-scope-dependencies.adoc#testing.test-scope-dependencies[#features.testing.test-scope-dependencies] -* xref:reference:testing/testcontainers.adoc#testing.testcontainers[#features.testing.testcontainers] -* xref:reference:testing/testcontainers.adoc#testing.testcontainers[#howto-testcontainers] -* xref:reference:testing/testcontainers.adoc#testing.testcontainers.dynamic-properties[#features.testing.testcontainers.dynamic-properties] -* xref:reference:testing/testcontainers.adoc#testing.testcontainers.service-connections[#features.testing.testcontainers.service-connections] -* xref:reference:testing/test-utilities.adoc#testing.utilities[#features.testing.utilities] -* xref:reference:testing/test-utilities.adoc#testing.utilities.config-data-application-context-initializer[#features.testing.utilities.config-data-application-context-initializer] -* xref:reference:testing/test-utilities.adoc#testing.utilities.output-capture[#features.testing.utilities.output-capture] -* xref:reference:testing/test-utilities.adoc#testing.utilities.test-property-values[#features.testing.utilities.test-property-values] -* xref:reference:testing/test-utilities.adoc#testing.utilities.test-rest-template[#features.testing.utilities.test-rest-template] -* xref:reference:io/caching.adoc#io.caching[#boot-features-caching] -* xref:reference:io/caching.adoc#io.caching[#io.caching] -* xref:reference:io/caching.adoc#io.caching.provider[#io.caching.provider] -* xref:reference:io/caching.adoc#io.caching.provider[#boot-features-caching-provider] * xref:reference:io/caching.adoc#io.caching.provider.cache2k[#io.caching.provider.cache2k] -* xref:reference:io/caching.adoc#io.caching.provider.caffeine[#io.caching.provider.caffeine] * xref:reference:io/caching.adoc#io.caching.provider.caffeine[#boot-features-caching-provider-caffeine] +* xref:reference:io/caching.adoc#io.caching.provider.caffeine[#features.caching.provider.caffeine] +* xref:reference:io/caching.adoc#io.caching.provider.caffeine[#io.caching.provider.caffeine] * xref:reference:io/caching.adoc#io.caching.provider.couchbase[#boot-features-caching-provider-couchbase] +* xref:reference:io/caching.adoc#io.caching.provider.couchbase[#features.caching.provider.couchbase] * xref:reference:io/caching.adoc#io.caching.provider.couchbase[#io.caching.provider.couchbase] -* xref:reference:io/caching.adoc#io.caching.provider.generic[#io.caching.provider.generic] * xref:reference:io/caching.adoc#io.caching.provider.generic[#boot-features-caching-provider-generic] -* xref:reference:io/caching.adoc#io.caching.provider.hazelcast[#io.caching.provider.hazelcast] +* xref:reference:io/caching.adoc#io.caching.provider.generic[#features.caching.provider.generic] +* xref:reference:io/caching.adoc#io.caching.provider.generic[#io.caching.provider.generic] * xref:reference:io/caching.adoc#io.caching.provider.hazelcast[#boot-features-caching-provider-hazelcast] +* xref:reference:io/caching.adoc#io.caching.provider.hazelcast[#features.caching.provider.hazelcast] +* xref:reference:io/caching.adoc#io.caching.provider.hazelcast[#io.caching.provider.hazelcast] * xref:reference:io/caching.adoc#io.caching.provider.infinispan[#boot-features-caching-provider-infinispan] +* xref:reference:io/caching.adoc#io.caching.provider.infinispan[#features.caching.provider.infinispan] * xref:reference:io/caching.adoc#io.caching.provider.infinispan[#io.caching.provider.infinispan] -* xref:reference:io/caching.adoc#io.caching.provider.jcache[#io.caching.provider.jcache] * xref:reference:io/caching.adoc#io.caching.provider.jcache[#boot-features-caching-provider-jcache] -* xref:reference:io/caching.adoc#io.caching.provider.none[#io.caching.provider.none] +* xref:reference:io/caching.adoc#io.caching.provider.jcache[#features.caching.provider.ehcache2] +* xref:reference:io/caching.adoc#io.caching.provider.jcache[#features.caching.provider.jcache] +* xref:reference:io/caching.adoc#io.caching.provider.jcache[#io.caching.provider.jcache] * xref:reference:io/caching.adoc#io.caching.provider.none[#boot-features-caching-provider-none] +* xref:reference:io/caching.adoc#io.caching.provider.none[#features.caching.provider.none] +* xref:reference:io/caching.adoc#io.caching.provider.none[#io.caching.provider.none] * xref:reference:io/caching.adoc#io.caching.provider.redis[#boot-features-caching-provider-redis] +* xref:reference:io/caching.adoc#io.caching.provider.redis[#features.caching.provider.redis] * xref:reference:io/caching.adoc#io.caching.provider.redis[#io.caching.provider.redis] -* xref:reference:io/caching.adoc#io.caching.provider.simple[#io.caching.provider.simple] * xref:reference:io/caching.adoc#io.caching.provider.simple[#boot-features-caching-provider-simple] +* xref:reference:io/caching.adoc#io.caching.provider.simple[#features.caching.provider.simple] +* xref:reference:io/caching.adoc#io.caching.provider.simple[#io.caching.provider.simple] +* xref:reference:io/caching.adoc#io.caching.provider[#boot-features-caching-provider] +* xref:reference:io/caching.adoc#io.caching.provider[#features.caching.provider] +* xref:reference:io/caching.adoc#io.caching.provider[#io.caching.provider] +* xref:reference:io/caching.adoc#io.caching[#boot-features-caching] +* xref:reference:io/caching.adoc#io.caching[#features.caching] +* xref:reference:io/caching.adoc#io.caching[#io.caching] * xref:reference:io/email.adoc#io.email[#boot-features-email] +* xref:reference:io/email.adoc#io.email[#features.email] * xref:reference:io/email.adoc#io.email[#io.email] * xref:reference:io/hazelcast.adoc#io.hazelcast[#boot-features-hazelcast] +* xref:reference:io/hazelcast.adoc#io.hazelcast[#features.hazelcast] * xref:reference:io/hazelcast.adoc#io.hazelcast[#io.hazelcast] * xref:reference:io/index.adoc#io[#io] -* xref:reference:io/jta.adoc#io.jta[#boot-features-jta] -* xref:reference:io/jta.adoc#io.jta[#io.jta] +* xref:reference:io/index.adoc[#io] +* xref:reference:io/index.adoc[io] * xref:reference:io/jta.adoc#io.jta.jakartaee[#boot-features-jta-javaee] +* xref:reference:io/jta.adoc#io.jta.jakartaee[#features.jta.javaee] * xref:reference:io/jta.adoc#io.jta.jakartaee[#io.jta.jakartaee] * xref:reference:io/jta.adoc#io.jta.mixing-xa-and-non-xa-connections[#boot-features-jta-mixed-jms] +* xref:reference:io/jta.adoc#io.jta.mixing-xa-and-non-xa-connections[#features.jta.mixing-xa-and-non-xa-connections] * xref:reference:io/jta.adoc#io.jta.mixing-xa-and-non-xa-connections[#io.jta.mixing-xa-and-non-xa-connections] -* xref:reference:io/jta.adoc#io.jta.supporting-embedded-transaction-manager[#io.jta.supporting-embedded-transaction-manager] * xref:reference:io/jta.adoc#io.jta.supporting-embedded-transaction-manager[#boot-features-jta-supporting-alternative-embedded] -* xref:reference:io/quartz.adoc#io.quartz[#io.quartz] +* xref:reference:io/jta.adoc#io.jta.supporting-embedded-transaction-manager[#features.jta.supporting-alternative-embedded-transaction-manager] +* xref:reference:io/jta.adoc#io.jta.supporting-embedded-transaction-manager[#io.jta.supporting-embedded-transaction-manager] +* xref:reference:io/jta.adoc#io.jta[#boot-features-jta] +* xref:reference:io/jta.adoc#io.jta[#features.jta] +* xref:reference:io/jta.adoc#io.jta[#io.jta] * xref:reference:io/quartz.adoc#io.quartz[#boot-features-quartz] -* xref:reference:io/rest-client.adoc#io.rest-client[#io.rest-client] +* xref:reference:io/quartz.adoc#io.quartz[#features.quartz] +* xref:reference:io/quartz.adoc#io.quartz[#io.quartz] * xref:reference:io/rest-client.adoc#io.rest-client.clienthttprequestfactory[#io.rest-client.clienthttprequestfactory] -* xref:reference:io/rest-client.adoc#io.rest-client.restclient[#io.rest-client.restclient] * xref:reference:io/rest-client.adoc#io.rest-client.restclient.customization[#io.rest-client.restclient.customization] * xref:reference:io/rest-client.adoc#io.rest-client.restclient.ssl[#io.rest-client.restclient.ssl] -* xref:reference:io/rest-client.adoc#io.rest-client.resttemplate[#io.rest-client.resttemplate] -* xref:reference:io/rest-client.adoc#io.rest-client.resttemplate[#boot-features-resttemplate] -* xref:reference:io/rest-client.adoc#io.rest-client.resttemplate.customization[#io.rest-client.resttemplate.customization] +* xref:reference:io/rest-client.adoc#io.rest-client.restclient[#io.rest-client.restclient] * xref:reference:io/rest-client.adoc#io.rest-client.resttemplate.customization[#boot-features-resttemplate-customization] +* xref:reference:io/rest-client.adoc#io.rest-client.resttemplate.customization[#features.resttemplate.customization] +* xref:reference:io/rest-client.adoc#io.rest-client.resttemplate.customization[#io.rest-client.resttemplate.customization] * xref:reference:io/rest-client.adoc#io.rest-client.resttemplate.ssl[#io.rest-client.resttemplate.ssl] -* xref:reference:io/rest-client.adoc#io.rest-client.webclient[#io.rest-client.webclient] -* xref:reference:io/rest-client.adoc#io.rest-client.webclient[#boot-features-webclient] +* xref:reference:io/rest-client.adoc#io.rest-client.resttemplate[#boot-features-resttemplate] +* xref:reference:io/rest-client.adoc#io.rest-client.resttemplate[#features.resttemplate] +* xref:reference:io/rest-client.adoc#io.rest-client.resttemplate[#io.rest-client.resttemplate] * xref:reference:io/rest-client.adoc#io.rest-client.webclient.customization[#boot-features-webclient-customization] +* xref:reference:io/rest-client.adoc#io.rest-client.webclient.customization[#features.webclient.customization] * xref:reference:io/rest-client.adoc#io.rest-client.webclient.customization[#io.rest-client.webclient.customization] * xref:reference:io/rest-client.adoc#io.rest-client.webclient.runtime[#boot-features-webclient-runtime] +* xref:reference:io/rest-client.adoc#io.rest-client.webclient.runtime[#features.webclient.runtime] * xref:reference:io/rest-client.adoc#io.rest-client.webclient.runtime[#io.rest-client.webclient.runtime] * xref:reference:io/rest-client.adoc#io.rest-client.webclient.ssl[#io.rest-client.webclient.ssl] +* xref:reference:io/rest-client.adoc#io.rest-client.webclient[#boot-features-webclient] +* xref:reference:io/rest-client.adoc#io.rest-client.webclient[#features.webclient] +* xref:reference:io/rest-client.adoc#io.rest-client.webclient[#io.rest-client.webclient] +* xref:reference:io/rest-client.adoc#io.rest-client[#io.rest-client] * xref:reference:io/validation.adoc#io.validation[#boot-features-validation] +* xref:reference:io/validation.adoc#io.validation[#features.validation] * xref:reference:io/validation.adoc#io.validation[#io.validation] -* xref:reference:io/webservices.adoc#io.webservices[#boot-features-webservices] -* xref:reference:io/webservices.adoc#io.webservices[#io.webservices] * xref:reference:io/webservices.adoc#io.webservices.template[#boot-features-webservices-template] +* xref:reference:io/webservices.adoc#io.webservices.template[#features.webservices.template] * xref:reference:io/webservices.adoc#io.webservices.template[#io.webservices.template] -* xref:reference:messaging/amqp.adoc#messaging.amqp[#boot-features-amqp] -* xref:reference:messaging/amqp.adoc#messaging.amqp[#messaging.amqp] +* xref:reference:io/webservices.adoc#io.webservices[#boot-features-webservices] +* xref:reference:io/webservices.adoc#io.webservices[#features.webservices] +* xref:reference:io/webservices.adoc#io.webservices[#io.webservices] * xref:reference:messaging/amqp.adoc#messaging.amqp.rabbitmq[#boot-features-rabbitmq] +* xref:reference:messaging/amqp.adoc#messaging.amqp.rabbitmq[#features.messaging.amqp.rabbit] +* xref:reference:messaging/amqp.adoc#messaging.amqp.rabbitmq[#messaging.amqp.rabbit] * xref:reference:messaging/amqp.adoc#messaging.amqp.rabbitmq[#messaging.amqp.rabbitmq] -* xref:reference:messaging/amqp.adoc#messaging.amqp.receiving[#messaging.amqp.receiving] * xref:reference:messaging/amqp.adoc#messaging.amqp.receiving[#boot-features-using-amqp-receiving] +* xref:reference:messaging/amqp.adoc#messaging.amqp.receiving[#features.messaging.amqp.receiving] +* xref:reference:messaging/amqp.adoc#messaging.amqp.receiving[#messaging.amqp.receiving] +* xref:reference:messaging/amqp.adoc#messaging.amqp.sending-stream[#messaging.amqp.sending-stream] * xref:reference:messaging/amqp.adoc#messaging.amqp.sending[#boot-features-using-amqp-sending] +* xref:reference:messaging/amqp.adoc#messaging.amqp.sending[#features.messaging.amqp.sending] * xref:reference:messaging/amqp.adoc#messaging.amqp.sending[#messaging.amqp.sending] -* xref:reference:messaging/amqp.adoc#messaging.amqp.sending-stream[#messaging.amqp.sending-stream] +* xref:reference:messaging/amqp.adoc#messaging.amqp[#boot-features-amqp] +* xref:reference:messaging/amqp.adoc#messaging.amqp[#features.messaging.amqp] +* xref:reference:messaging/amqp.adoc#messaging.amqp[#messaging.amqp] * xref:reference:messaging/index.adoc#messaging[#boot-features-messaging] +* xref:reference:messaging/index.adoc#messaging[#features.messaging] * xref:reference:messaging/index.adoc#messaging[#messaging] -* xref:reference:messaging/jms.adoc#messaging.jms[#boot-features-jms] -* xref:reference:messaging/jms.adoc#messaging.jms[#messaging.jms] +* xref:reference:messaging/index.adoc[#messaging] +* xref:reference:messaging/index.adoc[messaging] * xref:reference:messaging/jms.adoc#messaging.jms.activemq[#boot-features-activemq] +* xref:reference:messaging/jms.adoc#messaging.jms.activemq[#features.messaging.jms.activemq] * xref:reference:messaging/jms.adoc#messaging.jms.activemq[#messaging.jms.activemq] -* xref:reference:messaging/jms.adoc#messaging.jms.artemis[#messaging.jms.artemis] * xref:reference:messaging/jms.adoc#messaging.jms.artemis[#boot-features-artemis] +* xref:reference:messaging/jms.adoc#messaging.jms.artemis[#features.messaging.jms.artemis] +* xref:reference:messaging/jms.adoc#messaging.jms.artemis[#messaging.jms.artemis] * xref:reference:messaging/jms.adoc#messaging.jms.jndi[#boot-features-jms-jndi] +* xref:reference:messaging/jms.adoc#messaging.jms.jndi[#features.messaging.jms.jndi] * xref:reference:messaging/jms.adoc#messaging.jms.jndi[#messaging.jms.jndi] * xref:reference:messaging/jms.adoc#messaging.jms.receiving[#boot-features-using-jms-receiving] +* xref:reference:messaging/jms.adoc#messaging.jms.receiving[#features.messaging.jms.receiving] * xref:reference:messaging/jms.adoc#messaging.jms.receiving[#messaging.jms.receiving] * xref:reference:messaging/jms.adoc#messaging.jms.sending[#boot-features-using-jms-sending] +* xref:reference:messaging/jms.adoc#messaging.jms.sending[#features.messaging.jms.sending] * xref:reference:messaging/jms.adoc#messaging.jms.sending[#messaging.jms.sending] -* xref:reference:messaging/kafka.adoc#messaging.kafka[#messaging.kafka] -* xref:reference:messaging/kafka.adoc#messaging.kafka[#boot-features-kafka] +* xref:reference:messaging/jms.adoc#messaging.jms[#boot-features-jms] +* xref:reference:messaging/jms.adoc#messaging.jms[#features.messaging.jms] +* xref:reference:messaging/jms.adoc#messaging.jms[#messaging.jms] * xref:reference:messaging/kafka.adoc#messaging.kafka.additional-properties[#boot-features-kafka-extra-props] +* xref:reference:messaging/kafka.adoc#messaging.kafka.additional-properties[#features.messaging.kafka.additional-properties] * xref:reference:messaging/kafka.adoc#messaging.kafka.additional-properties[#messaging.kafka.additional-properties] * xref:reference:messaging/kafka.adoc#messaging.kafka.embedded[#boot-features-embedded-kafka] +* xref:reference:messaging/kafka.adoc#messaging.kafka.embedded[#features.messaging.kafka.embedded] * xref:reference:messaging/kafka.adoc#messaging.kafka.embedded[#messaging.kafka.embedded] -* xref:reference:messaging/kafka.adoc#messaging.kafka.receiving[#messaging.kafka.receiving] * xref:reference:messaging/kafka.adoc#messaging.kafka.receiving[#boot-features-kafka-receiving-a-message] -* xref:reference:messaging/kafka.adoc#messaging.kafka.sending[#messaging.kafka.sending] +* xref:reference:messaging/kafka.adoc#messaging.kafka.receiving[#features.messaging.kafka.receiving] +* xref:reference:messaging/kafka.adoc#messaging.kafka.receiving[#messaging.kafka.receiving] * xref:reference:messaging/kafka.adoc#messaging.kafka.sending[#boot-features-kafka-sending-a-message] -* xref:reference:messaging/kafka.adoc#messaging.kafka.streams[#messaging.kafka.streams] +* xref:reference:messaging/kafka.adoc#messaging.kafka.sending[#features.messaging.kafka.sending] +* xref:reference:messaging/kafka.adoc#messaging.kafka.sending[#messaging.kafka.sending] * xref:reference:messaging/kafka.adoc#messaging.kafka.streams[#boot-features-kafka-streams] -* xref:reference:messaging/pulsar.adoc#messaging.pulsar[#messaging.pulsar] +* xref:reference:messaging/kafka.adoc#messaging.kafka.streams[#features.messaging.kafka.streams] +* xref:reference:messaging/kafka.adoc#messaging.kafka.streams[#messaging.kafka.streams] +* xref:reference:messaging/kafka.adoc#messaging.kafka[#boot-features-kafka] +* xref:reference:messaging/kafka.adoc#messaging.kafka[#features.messaging.kafka] +* xref:reference:messaging/kafka.adoc#messaging.kafka[#messaging.kafka] * xref:reference:messaging/pulsar.adoc#messaging.pulsar.additional-properties[#messaging.pulsar.additional-properties] -* xref:reference:messaging/pulsar.adoc#messaging.pulsar.admin[#messaging.pulsar.admin] * xref:reference:messaging/pulsar.adoc#messaging.pulsar.admin.auth[#messaging.pulsar.admin.auth] -* xref:reference:messaging/pulsar.adoc#messaging.pulsar.connecting[#messaging.pulsar.connecting] +* xref:reference:messaging/pulsar.adoc#messaging.pulsar.admin[#messaging.pulsar.admin] * xref:reference:messaging/pulsar.adoc#messaging.pulsar.connecting-reactive[#messaging.pulsar.connecting-reactive] * xref:reference:messaging/pulsar.adoc#messaging.pulsar.connecting.auth[#messaging.pulsar.connecting.auth] * xref:reference:messaging/pulsar.adoc#messaging.pulsar.connecting.ssl[#messaging.pulsar.connecting.ssl] -* xref:reference:messaging/pulsar.adoc#messaging.pulsar.reading[#messaging.pulsar.reading] +* xref:reference:messaging/pulsar.adoc#messaging.pulsar.connecting[#messaging.pulsar.connecting] * xref:reference:messaging/pulsar.adoc#messaging.pulsar.reading-reactive[#messaging.pulsar.reading-reactive] -* xref:reference:messaging/pulsar.adoc#messaging.pulsar.receiving[#messaging.pulsar.receiving] +* xref:reference:messaging/pulsar.adoc#messaging.pulsar.reading[#messaging.pulsar.reading] * xref:reference:messaging/pulsar.adoc#messaging.pulsar.receiving-reactive[#messaging.pulsar.receiving-reactive] -* xref:reference:messaging/pulsar.adoc#messaging.pulsar.sending[#messaging.pulsar.sending] +* xref:reference:messaging/pulsar.adoc#messaging.pulsar.receiving[#messaging.pulsar.receiving] * xref:reference:messaging/pulsar.adoc#messaging.pulsar.sending-reactive[#messaging.pulsar.sending-reactive] -* xref:reference:messaging/rsocket.adoc#messaging.rsocket[#messaging.rsocket] -* xref:reference:messaging/rsocket.adoc#messaging.rsocket[#boot-features-rsocket] +* xref:reference:messaging/pulsar.adoc#messaging.pulsar.sending[#messaging.pulsar.sending] +* xref:reference:messaging/pulsar.adoc#messaging.pulsar[#messaging.pulsar] * xref:reference:messaging/rsocket.adoc#messaging.rsocket.messaging[#boot-features-rsocket-messaging] +* xref:reference:messaging/rsocket.adoc#messaging.rsocket.messaging[#features.rsocket.messaging] * xref:reference:messaging/rsocket.adoc#messaging.rsocket.messaging[#messaging.rsocket.messaging] -* xref:reference:messaging/rsocket.adoc#messaging.rsocket.requester[#messaging.rsocket.requester] * xref:reference:messaging/rsocket.adoc#messaging.rsocket.requester[#boot-features-rsocket-requester] -* xref:reference:messaging/rsocket.adoc#messaging.rsocket.server-auto-configuration[#messaging.rsocket.server-auto-configuration] +* xref:reference:messaging/rsocket.adoc#messaging.rsocket.requester[#features.rsocket.requester] +* xref:reference:messaging/rsocket.adoc#messaging.rsocket.requester[#messaging.rsocket.requester] * xref:reference:messaging/rsocket.adoc#messaging.rsocket.server-auto-configuration[#boot-features-rsocket-server-auto-configuration] -* xref:reference:messaging/rsocket.adoc#messaging.rsocket.strategies-auto-configuration[#messaging.rsocket.strategies-auto-configuration] +* xref:reference:messaging/rsocket.adoc#messaging.rsocket.server-auto-configuration[#features.rsocket.server-auto-configuration] +* xref:reference:messaging/rsocket.adoc#messaging.rsocket.server-auto-configuration[#messaging.rsocket.server-auto-configuration] * xref:reference:messaging/rsocket.adoc#messaging.rsocket.strategies-auto-configuration[#boot-features-rsocket-strategies-auto-configuration] -* xref:reference:messaging/spring-integration.adoc#messaging.spring-integration[#messaging.spring-integration] +* xref:reference:messaging/rsocket.adoc#messaging.rsocket.strategies-auto-configuration[#features.rsocket.strategies-auto-configuration] +* xref:reference:messaging/rsocket.adoc#messaging.rsocket.strategies-auto-configuration[#messaging.rsocket.strategies-auto-configuration] +* xref:reference:messaging/rsocket.adoc#messaging.rsocket[#boot-features-rsocket] +* xref:reference:messaging/rsocket.adoc#messaging.rsocket[#features.rsocket] +* xref:reference:messaging/rsocket.adoc#messaging.rsocket[#messaging.rsocket] * xref:reference:messaging/spring-integration.adoc#messaging.spring-integration[#boot-features-integration] +* xref:reference:messaging/spring-integration.adoc#messaging.spring-integration[#features.spring-integration] +* xref:reference:messaging/spring-integration.adoc#messaging.spring-integration[#messaging.spring-integration] * xref:reference:messaging/websockets.adoc#messaging.websockets[#boot-features-websockets] +* xref:reference:messaging/websockets.adoc#messaging.websockets[#features.websockets] * xref:reference:messaging/websockets.adoc#messaging.websockets[#messaging.websockets] -* xref:reference:packaging/native-image/advanced-topics.adoc#packaging.native-image.advanced[#native-image.advanced] -* xref:reference:packaging/native-image/advanced-topics.adoc#packaging.native-image.advanced.converting-executable-jars[#native-image.advanced.converting-executable-jars] +* xref:reference:packaging/aot.adoc#packaging.aot[#deployment.efficient.aot] +* xref:reference:packaging/checkpoint-restore.adoc#packaging.checkpoint-restore[#deployment.efficient.checkpoint-restore] +* xref:reference:packaging/container-images/cloud-native-buildpacks.adoc#packaging.container-images.buildpacks[#boot-features-container-images-buildpacks] +* xref:reference:packaging/container-images/cloud-native-buildpacks.adoc#packaging.container-images.buildpacks[#container-images.buildpacks] +* xref:reference:packaging/container-images/cloud-native-buildpacks.adoc#packaging.container-images.buildpacks[#features.container-images.building.buildpacks] +* xref:reference:packaging/container-images/dockerfiles.adoc#packaging.container-images.dockerfiles[#boot-features-container-images-docker] +* xref:reference:packaging/container-images/dockerfiles.adoc#packaging.container-images.dockerfiles[#container-images.dockerfiles] +* xref:reference:packaging/container-images/dockerfiles.adoc#packaging.container-images.dockerfiles[#features.container-images.building.dockerfiles] +* xref:reference:packaging/container-images/efficient-images.adoc#packaging.container-images.efficient-images.layering[#boot-layering-docker-images] +* xref:reference:packaging/container-images/efficient-images.adoc#packaging.container-images.efficient-images.layering[#container-images.efficient-images.layering] +* xref:reference:packaging/container-images/efficient-images.adoc#packaging.container-images.efficient-images.layering[#features.container-images.layering] +* xref:reference:packaging/container-images/efficient-images.adoc#packaging.container-images.efficient-images[#boot-features-container-images-building] +* xref:reference:packaging/container-images/efficient-images.adoc#packaging.container-images.efficient-images[#boot-features-container-images] +* xref:reference:packaging/container-images/efficient-images.adoc#packaging.container-images.efficient-images[#container-images.efficient-images] +* xref:reference:packaging/container-images/efficient-images.adoc#packaging.container-images.efficient-images[#features.container-images.building] +* xref:reference:packaging/container-images/index.adoc#packaging.container-images[#container-images] +* xref:reference:packaging/container-images/index.adoc[#container-images] +* xref:reference:packaging/container-images/index.adoc[container-images] +* xref:reference:packaging/efficient.adoc#packaging.efficient.unpacking[#container-images.efficient-images.unpacking] +* xref:reference:packaging/efficient.adoc#packaging.efficient.unpacking[#containers-deployment] +* xref:reference:packaging/efficient.adoc#packaging.efficient.unpacking[#deployment.containers] +* xref:reference:packaging/efficient.adoc#packaging.efficient.unpacking[#deployment.efficient.unpacking] +* xref:reference:packaging/efficient.adoc#packaging.efficient[#deployment.efficient] * xref:reference:packaging/native-image/advanced-topics.adoc#packaging.native-image.advanced.converting-executable-jars.buildpacks[#native-image.advanced.converting-executable-jars.buildpacks] * xref:reference:packaging/native-image/advanced-topics.adoc#packaging.native-image.advanced.converting-executable-jars.native-image[#native-image.advanced.converting-executable-jars.native-image] -* xref:reference:packaging/native-image/advanced-topics.adoc#packaging.native-image.advanced.custom-hints[#native-image.advanced.custom-hints] +* xref:reference:packaging/native-image/advanced-topics.adoc#packaging.native-image.advanced.converting-executable-jars[#native-image.advanced.converting-executable-jars] * xref:reference:packaging/native-image/advanced-topics.adoc#packaging.native-image.advanced.custom-hints.testing[#native-image.advanced.custom-hints.testing] +* xref:reference:packaging/native-image/advanced-topics.adoc#packaging.native-image.advanced.custom-hints[#native-image.advanced.custom-hints] * xref:reference:packaging/native-image/advanced-topics.adoc#packaging.native-image.advanced.known-limitations[#native-image.advanced.known-limitations] * xref:reference:packaging/native-image/advanced-topics.adoc#packaging.native-image.advanced.nested-configuration-properties[#native-image.advanced.nested-configuration-properties] -* xref:reference:packaging/native-image/advanced-topics.adoc#packaging.native-image.advanced.using-the-tracing-agent[#native-image.advanced.using-the-tracing-agent] * xref:reference:packaging/native-image/advanced-topics.adoc#packaging.native-image.advanced.using-the-tracing-agent.launch[#native-image.advanced.using-the-tracing-agent.launch] -* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application[#native-image.developing-your-first-application] -* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.buildpacks[#native-image.developing-your-first-application.buildpacks] -* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.buildpacks.gradle[#native-image.developing-your-first-application.buildpacks.gradle] -* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.buildpacks.maven[#native-image.developing-your-first-application.buildpacks.maven] -* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.buildpacks.running[#native-image.developing-your-first-application.buildpacks.running] -* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.buildpacks.system-requirements[#native-image.developing-your-first-application.buildpacks.system-requirements] -* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.native-build-tools[#native-image.developing-your-first-application.native-build-tools] -* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.native-build-tools.gradle[#native-image.developing-your-first-application.native-build-tools.gradle] -* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.native-build-tools.maven[#native-image.developing-your-first-application.native-build-tools.maven] -* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.native-build-tools.prerequisites[#native-image.developing-your-first-application.native-build-tools.prerequisites] -* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.native-build-tools.prerequisites.linux-macos[#native-image.developing-your-first-application.native-build-tools.prerequisites.linux-macos] -* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.native-build-tools.prerequisites.windows[#native-image.developing-your-first-application.native-build-tools.prerequisites.windows] -* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.native-build-tools.running[#native-image.developing-your-first-application.native-build-tools.running] -* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.sample-application[#native-image.developing-your-first-application.sample-application] +* xref:reference:packaging/native-image/advanced-topics.adoc#packaging.native-image.advanced.using-the-tracing-agent[#native-image.advanced.using-the-tracing-agent] +* xref:reference:packaging/native-image/advanced-topics.adoc#packaging.native-image.advanced[#native-image.advanced] * xref:reference:packaging/native-image/index.adoc#packaging.native-image[#native-image] -* xref:reference:packaging/native-image/introducing-graalvm-native-images.adoc#packaging.native-image.introducing-graalvm-native-images[#native-image.introducing-graalvm-native-images] +* xref:reference:packaging/native-image/index.adoc[#native-image] +* xref:reference:packaging/native-image/index.adoc[native-image] * xref:reference:packaging/native-image/introducing-graalvm-native-images.adoc#packaging.native-image.introducing-graalvm-native-images.key-differences-with-jvm-deployments[#packaging.native-image.introducing-graalvm-native-images.key-differences-with-jvm-deployments] -* xref:reference:packaging/native-image/introducing-graalvm-native-images.adoc#packaging.native-image.introducing-graalvm-native-images.understanding-aot-processing[#packaging.native-image.introducing-graalvm-native-images.understanding-aot-processing] * xref:reference:packaging/native-image/introducing-graalvm-native-images.adoc#packaging.native-image.introducing-graalvm-native-images.understanding-aot-processing.hint-file-generation[#packaging.native-image.introducing-graalvm-native-images.understanding-aot-processing.hint-file-generation] * xref:reference:packaging/native-image/introducing-graalvm-native-images.adoc#packaging.native-image.introducing-graalvm-native-images.understanding-aot-processing.proxy-class-generation[#packaging.native-image.introducing-graalvm-native-images.understanding-aot-processing.proxy-class-generation] * xref:reference:packaging/native-image/introducing-graalvm-native-images.adoc#packaging.native-image.introducing-graalvm-native-images.understanding-aot-processing.source-code-generation[#packaging.native-image.introducing-graalvm-native-images.understanding-aot-processing.source-code-generation] -* xref:how-to:native-image/testing-native-applications.adoc#howto.native-image.testing[#native-image.testing] -* xref:how-to:native-image/testing-native-applications.adoc#howto.native-image.testing.with-native-build-tools[#native-image.testing.with-native-build-tools] -* xref:how-to:native-image/testing-native-applications.adoc#howto.native-image.testing.with-native-build-tools.gradle[#native-image.testing.with-native-build-tools.gradle] -* xref:how-to:native-image/testing-native-applications.adoc#howto.native-image.testing.with-native-build-tools.maven[#native-image.testing.with-native-build-tools.maven] -* xref:how-to:native-image/testing-native-applications.adoc#howto.native-image.testing.with-the-jvm[#native-image.testing.with-the-jvm] -* xref:reference:using/auto-configuration.adoc#using.auto-configuration[#using.auto-configuration] +* xref:reference:packaging/native-image/introducing-graalvm-native-images.adoc#packaging.native-image.introducing-graalvm-native-images.understanding-aot-processing[#packaging.native-image.introducing-graalvm-native-images.understanding-aot-processing] +* xref:reference:packaging/native-image/introducing-graalvm-native-images.adoc#packaging.native-image.introducing-graalvm-native-images[#native-image.introducing-graalvm-native-images] +* xref:reference:testing/index.adoc#testing[#boot-features-testing] +* xref:reference:testing/index.adoc#testing[#features.testing] +* xref:reference:testing/spring-applications.adoc#testing.spring-applications[#boot-features-testing-spring-applications] +* xref:reference:testing/spring-applications.adoc#testing.spring-applications[#features.testing.spring-applications] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.additional-autoconfiguration-and-slicing[#boot-features-testing-spring-boot-applications-testing-auto-configured-additional-auto-config] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.additional-autoconfiguration-and-slicing[#features.testing.spring-boot-applications.additional-autoconfiguration-and-slicing] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-jdbc[#boot-features-testing-spring-boot-applications-testing-autoconfigured-jdbc-test] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-jdbc[#features.testing.spring-boot-applications.autoconfigured-jdbc] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-jooq[#boot-features-testing-spring-boot-applications-testing-autoconfigured-jooq-test] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-jooq[#features.testing.spring-boot-applications.autoconfigured-jooq] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-rest-client[#boot-features-testing-spring-boot-applications-testing-autoconfigured-rest-client] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-rest-client[#features.testing.spring-boot-applications.autoconfigured-rest-client] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-cassandra[#boot-features-testing-spring-boot-applications-testing-autoconfigured-cassandra-test] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-cassandra[#features.testing.spring-boot-applications.autoconfigured-spring-data-cassandra] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-couchbase[#features.testing.spring-boot-applications.autoconfigured-spring-data-couchbase] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-elasticsearch[#features.testing.spring-boot-applications.autoconfigured-spring-data-elasticsearch] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-jdbc[#boot-features-testing-spring-boot-applications-testing-autoconfigured-data-jdbc-test] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-jdbc[#features.testing.spring-boot-applications.autoconfigured-spring-data-jdbc] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-jpa[#boot-features-testing-spring-boot-applications-testing-autoconfigured-jpa-test] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-jpa[#features.testing.spring-boot-applications.autoconfigured-spring-data-jpa] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-ldap[#boot-features-testing-spring-boot-applications-testing-autoconfigured-ldap-test] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-ldap[#features.testing.spring-boot-applications.autoconfigured-spring-data-ldap] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-mongodb[#boot-features-testing-spring-boot-applications-testing-autoconfigured-mongo-test] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-mongodb[#features.testing.spring-boot-applications.autoconfigured-spring-data-mongodb] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-neo4j[#boot-features-testing-spring-boot-applications-testing-autoconfigured-neo4j-test] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-neo4j[#features.testing.spring-boot-applications.autoconfigured-spring-data-neo4j] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-r2dbc[#features.testing.spring-boot-applications.autoconfigured-spring-data-r2dbc] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-redis[#boot-features-testing-spring-boot-applications-testing-autoconfigured-redis-test] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-redis[#features.testing.spring-boot-applications.autoconfigured-spring-data-redis] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-restdocs.with-mock-mvc[#boot-features-testing-spring-boot-applications-testing-autoconfigured-rest-docs-mock-mvc] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-restdocs.with-mock-mvc[#features.testing.spring-boot-applications.autoconfigured-spring-restdocs.with-mock-mvc] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-restdocs.with-rest-assured[#boot-features-testing-spring-boot-applications-testing-autoconfigured-rest-docs-rest-assured] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-restdocs.with-rest-assured[#features.testing.spring-boot-applications.autoconfigured-spring-restdocs.with-rest-assured] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-restdocs.with-web-test-client[#boot-features-testing-spring-boot-applications-testing-autoconfigured-rest-docs-web-test-client] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-restdocs.with-web-test-client[#features.testing.spring-boot-applications.autoconfigured-spring-restdocs.with-web-test-client] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-restdocs[#boot-features-testing-spring-boot-applications-testing-autoconfigured-rest-docs] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-restdocs[#features.testing.spring-boot-applications.autoconfigured-spring-restdocs] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-tests[#boot-features-testing-spring-boot-applications-testing-autoconfigured-tests] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-tests[#features.testing.spring-boot-applications.autoconfigured-tests] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-webservices.client[#features.testing.spring-boot-applications.autoconfigured-webservices.client] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-webservices.server[#features.testing.spring-boot-applications.autoconfigured-webservices.server] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-webservices[#boot-features-testing-spring-boot-applications-testing-autoconfigured-webservices] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-webservices[#features.testing.spring-boot-applications.autoconfigured-webservices] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.customizing-web-test-client[#boot-features-testing-spring-boot-applications-customizing-web-test-client] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.customizing-web-test-client[#features.testing.spring-boot-applications.customizing-web-test-client] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.detecting-configuration[#boot-features-testing-spring-boot-applications-detecting-config] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.detecting-configuration[#features.testing.spring-boot-applications.detecting-configuration] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.detecting-web-app-type[#boot-features-testing-spring-boot-applications-detecting-web-app-type] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.detecting-web-app-type[#features.testing.spring-boot-applications.detecting-web-app-type] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.excluding-configuration[#boot-features-testing-spring-boot-applications-excluding-config] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.excluding-configuration[#features.testing.spring-boot-applications.excluding-configuration] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.jmx[#boot-features-testing-spring-boot-applications-jmx] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.jmx[#features.testing.spring-boot-applications.jmx] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.json-tests[#boot-features-testing-spring-boot-applications-testing-autoconfigured-json-tests] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.json-tests[#features.testing.spring-boot-applications.json-tests] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.metrics[#boot-features-testing-spring-boot-applications-metrics] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.metrics[#features.testing.spring-boot-applications.metrics] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.mocking-beans[#boot-features-testing-spring-boot-applications-mocking-beans] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.mocking-beans[#features.testing.spring-boot-applications.mocking-beans] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.observations[#features.testing.spring-boot-applications.observations] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.spock[#boot-features-testing-spring-boot-applications-with-spock] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.spock[#features.testing.spring-boot-applications.spock] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.spring-graphql-tests[#features.testing.spring-boot-applications.spring-graphql-tests] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.spring-mvc-tests[#boot-features-testing-spring-boot-applications-testing-autoconfigured-mvc-tests] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.spring-mvc-tests[#features.testing.spring-boot-applications.spring-mvc-tests] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.spring-webflux-tests[#boot-features-testing-spring-boot-applications-testing-autoconfigured-webflux-tests] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.spring-webflux-tests[#features.testing.spring-boot-applications.spring-webflux-tests] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.tracing[#features.testing.spring-boot-applications.tracing] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.user-configuration-and-slicing[#boot-features-testing-spring-boot-applications-testing-user-configuration] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.user-configuration-and-slicing[#features.testing.spring-boot-applications.user-configuration-and-slicing] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.using-application-arguments[#boot-features-testing-spring-boot-application-arguments] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.using-application-arguments[#features.testing.spring-boot-applications.using-application-arguments] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.using-main[#features.testing.spring-boot-applications.using-main] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.with-mock-environment[#boot-features-testing-spring-boot-applications-testing-with-mock-environment] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.with-mock-environment[#features.testing.spring-boot-applications.with-mock-environment] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.with-running-server[#boot-features-testing-spring-boot-applications-testing-with-running-server] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.with-running-server[#features.testing.spring-boot-applications.with-running-server] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications[#boot-features-testing-spring-boot-applications] +* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications[#features.testing.spring-boot-applications] +* xref:reference:testing/test-scope-dependencies.adoc#testing.test-scope-dependencies[#boot-features-test-scope-dependencies] +* xref:reference:testing/test-scope-dependencies.adoc#testing.test-scope-dependencies[#features.testing.test-scope-dependencies] +* xref:reference:testing/test-utilities.adoc#testing.utilities.config-data-application-context-initializer[#boot-features-configfileapplicationcontextinitializer-test-utility] +* xref:reference:testing/test-utilities.adoc#testing.utilities.config-data-application-context-initializer[#features.testing.utilities.config-data-application-context-initializer] +* xref:reference:testing/test-utilities.adoc#testing.utilities.output-capture[#boot-features-output-capture-test-utility] +* xref:reference:testing/test-utilities.adoc#testing.utilities.output-capture[#features.testing.utilities.output-capture] +* xref:reference:testing/test-utilities.adoc#testing.utilities.test-property-values[#boot-features-test-property-values] +* xref:reference:testing/test-utilities.adoc#testing.utilities.test-property-values[#features.testing.utilities.test-property-values] +* xref:reference:testing/test-utilities.adoc#testing.utilities.test-rest-template[#boot-features-rest-templates-test-utility] +* xref:reference:testing/test-utilities.adoc#testing.utilities.test-rest-template[#features.testing.utilities.test-rest-template] +* xref:reference:testing/test-utilities.adoc#testing.utilities[#boot-features-test-utilities] +* xref:reference:testing/test-utilities.adoc#testing.utilities[#features.testing.utilities] +* xref:reference:testing/testcontainers.adoc#testing.testcontainers.dynamic-properties[#features.testing.testcontainers.dynamic-properties] +* xref:reference:testing/testcontainers.adoc#testing.testcontainers.dynamic-properties[#howto.testing.testcontainers.dynamic-properties] +* xref:reference:testing/testcontainers.adoc#testing.testcontainers.service-connections[#features.testing.testcontainers.service-connections] +* xref:reference:testing/testcontainers.adoc#testing.testcontainers[#features.testing.testcontainers] +* xref:reference:testing/testcontainers.adoc#testing.testcontainers[#howto-testcontainers] +* xref:reference:testing/testcontainers.adoc#testing.testcontainers[#howto.testing.testcontainers] +* xref:reference:using/auto-configuration.adoc#using.auto-configuration.disabling-specific[#using-boot-disabling-specific-auto-configuration] * xref:reference:using/auto-configuration.adoc#using.auto-configuration.disabling-specific[#using.auto-configuration.disabling-specific] * xref:reference:using/auto-configuration.adoc#using.auto-configuration.packages[#using.auto-configuration.packages] +* xref:reference:using/auto-configuration.adoc#using.auto-configuration.replacing[#using-boot-replacing-auto-configuration] * xref:reference:using/auto-configuration.adoc#using.auto-configuration.replacing[#using.auto-configuration.replacing] -* xref:reference:using/build-systems.adoc#using.build-systems[#using.build-systems] +* xref:reference:using/auto-configuration.adoc#using.auto-configuration[#using-boot-auto-configuration] +* xref:reference:using/auto-configuration.adoc#using.auto-configuration[#using.auto-configuration] +* xref:reference:using/build-systems.adoc#using.build-systems.ant[#using-boot-ant] * xref:reference:using/build-systems.adoc#using.build-systems.ant[#using.build-systems.ant] +* xref:reference:using/build-systems.adoc#using.build-systems.dependency-management[#using-boot-dependency-management] * xref:reference:using/build-systems.adoc#using.build-systems.dependency-management[#using.build-systems.dependency-management] +* xref:reference:using/build-systems.adoc#using.build-systems.gradle[#build-tool-plugins.gradle] +* xref:reference:using/build-systems.adoc#using.build-systems.gradle[#using-boot-gradle] * xref:reference:using/build-systems.adoc#using.build-systems.gradle[#using.build-systems.gradle] +* xref:reference:using/build-systems.adoc#using.build-systems.maven[#build-tool-plugins.maven] +* xref:reference:using/build-systems.adoc#using.build-systems.maven[#using-boot-maven] * xref:reference:using/build-systems.adoc#using.build-systems.maven[#using.build-systems.maven] +* xref:reference:using/build-systems.adoc#using.build-systems.starters[#using-boot-starter] * xref:reference:using/build-systems.adoc#using.build-systems.starters[#using.build-systems.starters] -* xref:reference:using/configuration-classes.adoc#using.configuration-classes[#using.configuration-classes] +* xref:reference:using/build-systems.adoc#using.build-systems[#using-boot-build-systems] +* xref:reference:using/build-systems.adoc#using.build-systems[#using.build-systems] +* xref:reference:using/configuration-classes.adoc#using.configuration-classes.importing-additional-configuration[#using-boot-importing-configuration] * xref:reference:using/configuration-classes.adoc#using.configuration-classes.importing-additional-configuration[#using.configuration-classes.importing-additional-configuration] +* xref:reference:using/configuration-classes.adoc#using.configuration-classes.importing-xml-configuration[#using-boot-importing-xml-configuration] * xref:reference:using/configuration-classes.adoc#using.configuration-classes.importing-xml-configuration[#using.configuration-classes.importing-xml-configuration] -* xref:reference:using/devtools.adoc#using.devtools[#using.devtools] +* xref:reference:using/configuration-classes.adoc#using.configuration-classes[#using-boot-configuration-classes] +* xref:reference:using/configuration-classes.adoc#using.configuration-classes[#using.configuration-classes] * xref:reference:using/devtools.adoc#using.devtools.diagnosing-classloading-issues[#using.devtools.diagnosing-classloading-issues] -* xref:reference:using/devtools.adoc#using.devtools.globalsettings[#using.devtools.globalsettings] +* xref:reference:using/devtools.adoc#using.devtools.globalsettings.configuring-file-system-watcher[#configuring-file-system-watcher] * xref:reference:using/devtools.adoc#using.devtools.globalsettings.configuring-file-system-watcher[#using.devtools.globalsettings.configuring-file-system-watcher] +* xref:reference:using/devtools.adoc#using.devtools.globalsettings[#using-boot-devtools-globalsettings] +* xref:reference:using/devtools.adoc#using.devtools.globalsettings[#using.devtools.globalsettings] +* xref:reference:using/devtools.adoc#using.devtools.livereload[#using-boot-devtools-livereload] * xref:reference:using/devtools.adoc#using.devtools.livereload[#using.devtools.livereload] +* xref:reference:using/devtools.adoc#using.devtools.property-defaults[#using-boot-devtools-property-defaults] * xref:reference:using/devtools.adoc#using.devtools.property-defaults[#using.devtools.property-defaults] -* xref:reference:using/devtools.adoc#using.devtools.remote-applications[#using.devtools.remote-applications] +* xref:reference:using/devtools.adoc#using.devtools.remote-applications.client[#running-remote-client-application] * xref:reference:using/devtools.adoc#using.devtools.remote-applications.client[#using.devtools.remote-applications.client] +* xref:reference:using/devtools.adoc#using.devtools.remote-applications.update[#using-boot-devtools-remote-update] * xref:reference:using/devtools.adoc#using.devtools.remote-applications.update[#using.devtools.remote-applications.update] -* xref:reference:using/devtools.adoc#using.devtools.restart[#using.devtools.restart] +* xref:reference:using/devtools.adoc#using.devtools.remote-applications[#using-boot-devtools-remote] +* xref:reference:using/devtools.adoc#using.devtools.remote-applications[#using.devtools.remote-applications] +* xref:reference:using/devtools.adoc#using.devtools.restart.customizing-the-classload[#using-boot-devtools-customizing-classload] * xref:reference:using/devtools.adoc#using.devtools.restart.customizing-the-classload[#using.devtools.restart.customizing-the-classload] +* xref:reference:using/devtools.adoc#using.devtools.restart.disable[#using-boot-devtools-restart-disable] * xref:reference:using/devtools.adoc#using.devtools.restart.disable[#using.devtools.restart.disable] +* xref:reference:using/devtools.adoc#using.devtools.restart.excluding-resources[#using-boot-devtools-restart-exclude] * xref:reference:using/devtools.adoc#using.devtools.restart.excluding-resources[#using.devtools.restart.excluding-resources] +* xref:reference:using/devtools.adoc#using.devtools.restart.limitations[#using-boot-devtools-known-restart-limitations] * xref:reference:using/devtools.adoc#using.devtools.restart.limitations[#using.devtools.restart.limitations] +* xref:reference:using/devtools.adoc#using.devtools.restart.logging-condition-delta[#using-boot-devtools-restart-logging-condition-delta] * xref:reference:using/devtools.adoc#using.devtools.restart.logging-condition-delta[#using.devtools.restart.logging-condition-delta] +* xref:reference:using/devtools.adoc#using.devtools.restart.restart-vs-reload[#using-spring-boot-restart-vs-reload] * xref:reference:using/devtools.adoc#using.devtools.restart.restart-vs-reload[#using.devtools.restart.restart-vs-reload] +* xref:reference:using/devtools.adoc#using.devtools.restart.triggerfile[#using-boot-devtools-restart-triggerfile] * xref:reference:using/devtools.adoc#using.devtools.restart.triggerfile[#using.devtools.restart.triggerfile] +* xref:reference:using/devtools.adoc#using.devtools.restart.watching-additional-paths[#using-boot-devtools-restart-additional-paths] * xref:reference:using/devtools.adoc#using.devtools.restart.watching-additional-paths[#using.devtools.restart.watching-additional-paths] +* xref:reference:using/devtools.adoc#using.devtools.restart[#using-boot-devtools-restart] +* xref:reference:using/devtools.adoc#using.devtools.restart[#using.devtools.restart] +* xref:reference:using/devtools.adoc#using.devtools[#using-boot-devtools] +* xref:reference:using/devtools.adoc#using.devtools[#using.devtools] +* xref:reference:using/index.adoc#using[#using-boot] * xref:reference:using/index.adoc#using[#using] +* xref:reference:using/index.adoc#using[using] +* xref:reference:using/packaging-for-production.adoc#using.packaging-for-production[#using-boot-packaging-for-production] * xref:reference:using/packaging-for-production.adoc#using.packaging-for-production[#using.packaging-for-production] -* xref:reference:using/running-your-application.adoc#using.running-your-application[#using.running-your-application] +* xref:reference:using/running-your-application.adoc#using.running-your-application.as-a-packaged-application[#using-boot-running-as-a-packaged-application] * xref:reference:using/running-your-application.adoc#using.running-your-application.as-a-packaged-application[#using.running-your-application.as-a-packaged-application] +* xref:reference:using/running-your-application.adoc#using.running-your-application.from-an-ide[#using-boot-running-from-an-ide] * xref:reference:using/running-your-application.adoc#using.running-your-application.from-an-ide[#using.running-your-application.from-an-ide] +* xref:reference:using/running-your-application.adoc#using.running-your-application.hot-swapping[#using-boot-hot-swapping] * xref:reference:using/running-your-application.adoc#using.running-your-application.hot-swapping[#using.running-your-application.hot-swapping] +* xref:reference:using/running-your-application.adoc#using.running-your-application.with-the-gradle-plugin[#using-boot-running-with-the-gradle-plugin] * xref:reference:using/running-your-application.adoc#using.running-your-application.with-the-gradle-plugin[#using.running-your-application.with-the-gradle-plugin] +* xref:reference:using/running-your-application.adoc#using.running-your-application.with-the-maven-plugin[#using-boot-running-with-the-maven-plugin] * xref:reference:using/running-your-application.adoc#using.running-your-application.with-the-maven-plugin[#using.running-your-application.with-the-maven-plugin] +* xref:reference:using/running-your-application.adoc#using.running-your-application[#using-boot-running-your-application] +* xref:reference:using/running-your-application.adoc#using.running-your-application[#using.running-your-application] +* xref:reference:using/spring-beans-and-dependency-injection.adoc#using.spring-beans-and-dependency-injection[#using-boot-spring-beans-and-dependency-injection] * xref:reference:using/spring-beans-and-dependency-injection.adoc#using.spring-beans-and-dependency-injection[#using.spring-beans-and-dependency-injection] -* xref:reference:using/structuring-your-code.adoc#using.structuring-your-code[#using.structuring-your-code] +* xref:reference:using/structuring-your-code.adoc#using.structuring-your-code.locating-the-main-class[#using-boot-locating-the-main-class] * xref:reference:using/structuring-your-code.adoc#using.structuring-your-code.locating-the-main-class[#using.structuring-your-code.locating-the-main-class] +* xref:reference:using/structuring-your-code.adoc#using.structuring-your-code.using-the-default-package[#using-boot-using-the-default-package] * xref:reference:using/structuring-your-code.adoc#using.structuring-your-code.using-the-default-package[#using.structuring-your-code.using-the-default-package] +* xref:reference:using/structuring-your-code.adoc#using.structuring-your-code[#using-boot-structuring-your-code] +* xref:reference:using/structuring-your-code.adoc#using.structuring-your-code[#using.structuring-your-code] +* xref:reference:using/using-the-springbootapplication-annotation.adoc#using.using-the-springbootapplication-annotation[#using-boot-using-springbootapplication-annotation] * xref:reference:using/using-the-springbootapplication-annotation.adoc#using.using-the-springbootapplication-annotation[#using.using-the-springbootapplication-annotation] * xref:reference:web/graceful-shutdown.adoc#web.graceful-shutdown[#boot-features-graceful-shutdown] +* xref:reference:web/graceful-shutdown.adoc#web.graceful-shutdown[#features.graceful-shutdown] * xref:reference:web/graceful-shutdown.adoc#web.graceful-shutdown[#web.graceful-shutdown] * xref:reference:web/index.adoc#web[#boot-features-developing-web-applications] +* xref:reference:web/index.adoc#web[#features.developing-web-applications] * xref:reference:web/index.adoc#web[#web] -* xref:reference:web/reactive.adoc#web.reactive[#web.reactive] -* xref:reference:web/reactive.adoc#web.reactive.reactive-server[#web.reactive.reactive-server] -* xref:reference:web/reactive.adoc#web.reactive.reactive-server[#boot-features-reactive-server] -* xref:reference:web/reactive.adoc#web.reactive.reactive-server-resources-configuration[#web.reactive.reactive-server-resources-configuration] +* xref:reference:web/index.adoc[#web] +* xref:reference:web/index.adoc[web] * xref:reference:web/reactive.adoc#web.reactive.reactive-server-resources-configuration[#boot-features-reactive-server-resources] -* xref:reference:web/reactive.adoc#web.reactive.reactive-server.customizing[#web.reactive.reactive-server.customizing] +* xref:reference:web/reactive.adoc#web.reactive.reactive-server-resources-configuration[#features.developing-web-applications.reactive-server-resources-configuration] +* xref:reference:web/reactive.adoc#web.reactive.reactive-server-resources-configuration[#web.reactive.reactive-server-resources-configuration] * xref:reference:web/reactive.adoc#web.reactive.reactive-server.customizing.direct[#web.reactive.reactive-server.customizing.direct] * xref:reference:web/reactive.adoc#web.reactive.reactive-server.customizing.programmatic[#web.reactive.reactive-server.customizing.programmatic] -* xref:reference:web/reactive.adoc#web.reactive.webflux[#boot-features-webflux] -* xref:reference:web/reactive.adoc#web.reactive.webflux[#web.reactive.webflux] -* xref:reference:web/reactive.adoc#web.reactive.webflux.auto-configuration[#web.reactive.webflux.auto-configuration] +* xref:reference:web/reactive.adoc#web.reactive.reactive-server.customizing[#web.reactive.reactive-server.customizing] +* xref:reference:web/reactive.adoc#web.reactive.reactive-server[#boot-features-reactive-server] +* xref:reference:web/reactive.adoc#web.reactive.reactive-server[#features.developing-web-applications.reactive-server] +* xref:reference:web/reactive.adoc#web.reactive.reactive-server[#web.reactive.reactive-server] * xref:reference:web/reactive.adoc#web.reactive.webflux.auto-configuration[#boot-features-webflux-auto-configuration] +* xref:reference:web/reactive.adoc#web.reactive.webflux.auto-configuration[#features.developing-web-applications.spring-webflux.auto-configuration] +* xref:reference:web/reactive.adoc#web.reactive.webflux.auto-configuration[#web.reactive.webflux.auto-configuration] * xref:reference:web/reactive.adoc#web.reactive.webflux.conversion-service[#web.reactive.webflux.conversion-service] -* xref:reference:web/reactive.adoc#web.reactive.webflux.error-handling[#boot-features-webflux-error-handling] -* xref:reference:web/reactive.adoc#web.reactive.webflux.error-handling[#web.reactive.webflux.error-handling] * xref:reference:web/reactive.adoc#web.reactive.webflux.error-handling.error-pages[#boot-features-webflux-error-handling-custom-error-pages] +* xref:reference:web/reactive.adoc#web.reactive.webflux.error-handling.error-pages[#features.developing-web-applications.spring-webflux.error-pages] * xref:reference:web/reactive.adoc#web.reactive.webflux.error-handling.error-pages[#web.reactive.webflux.error-handling.error-pages] +* xref:reference:web/reactive.adoc#web.reactive.webflux.error-handling[#boot-features-webflux-error-handling] +* xref:reference:web/reactive.adoc#web.reactive.webflux.error-handling[#features.developing-web-applications.spring-webflux.error-handling] +* xref:reference:web/reactive.adoc#web.reactive.webflux.error-handling[#web.reactive.webflux.error-handling] * xref:reference:web/reactive.adoc#web.reactive.webflux.httpcodecs[#boot-features-webflux-httpcodecs] +* xref:reference:web/reactive.adoc#web.reactive.webflux.httpcodecs[#features.developing-web-applications.spring-webflux.httpcodecs] * xref:reference:web/reactive.adoc#web.reactive.webflux.httpcodecs[#web.reactive.webflux.httpcodecs] -* xref:reference:web/reactive.adoc#web.reactive.webflux.static-content[#web.reactive.webflux.static-content] * xref:reference:web/reactive.adoc#web.reactive.webflux.static-content[#boot-features-webflux-static-content] -* xref:reference:web/reactive.adoc#web.reactive.webflux.template-engines[#web.reactive.webflux.template-engines] +* xref:reference:web/reactive.adoc#web.reactive.webflux.static-content[#features.developing-web-applications.spring-webflux.static-context] +* xref:reference:web/reactive.adoc#web.reactive.webflux.static-content[#web.reactive.webflux.static-content] * xref:reference:web/reactive.adoc#web.reactive.webflux.template-engines[#boot-features-webflux-template-engines] +* xref:reference:web/reactive.adoc#web.reactive.webflux.template-engines[#features.developing-web-applications.spring-webflux.template-engines] +* xref:reference:web/reactive.adoc#web.reactive.webflux.template-engines[#web.reactive.webflux.template-engines] * xref:reference:web/reactive.adoc#web.reactive.webflux.web-filters[#boot-features-webflux-web-filters] +* xref:reference:web/reactive.adoc#web.reactive.webflux.web-filters[#features.developing-web-applications.spring-webflux.web-filters] * xref:reference:web/reactive.adoc#web.reactive.webflux.web-filters[#web.reactive.webflux.web-filters] * xref:reference:web/reactive.adoc#web.reactive.webflux.welcome-page[#boot-features-webflux-welcome-page] +* xref:reference:web/reactive.adoc#web.reactive.webflux.welcome-page[#features.developing-web-applications.spring-webflux.welcome-page] * xref:reference:web/reactive.adoc#web.reactive.webflux.welcome-page[#web.reactive.webflux.welcome-page] -* xref:reference:web/servlet.adoc#web.servlet[#web.servlet] -* xref:reference:web/servlet.adoc#web.servlet.embedded-container[#boot-features-embedded-container] -* xref:reference:web/servlet.adoc#web.servlet.embedded-container[#web.servlet.embedded-container] -* xref:reference:web/servlet.adoc#web.servlet.embedded-container.application-context[#web.servlet.embedded-container.application-context] +* xref:reference:web/reactive.adoc#web.reactive.webflux[#boot-features-webflux] +* xref:reference:web/reactive.adoc#web.reactive.webflux[#features.developing-web-applications.spring-webflux] +* xref:reference:web/reactive.adoc#web.reactive.webflux[#web.reactive.webflux] +* xref:reference:web/reactive.adoc#web.reactive[#web.reactive] * xref:reference:web/servlet.adoc#web.servlet.embedded-container.application-context[#boot-features-embedded-container-application-context] -* xref:reference:web/servlet.adoc#web.servlet.embedded-container.context-initializer[#web.servlet.embedded-container.context-initializer] -* xref:reference:web/servlet.adoc#web.servlet.embedded-container.context-initializer[#boot-features-embedded-container-context-initializer] +* xref:reference:web/servlet.adoc#web.servlet.embedded-container.application-context[#features.developing-web-applications.embedded-container.application-context] +* xref:reference:web/servlet.adoc#web.servlet.embedded-container.application-context[#web.servlet.embedded-container.application-context] * xref:reference:web/servlet.adoc#web.servlet.embedded-container.context-initializer.scanning[#boot-features-embedded-container-servlets-filters-listeners-scanning] +* xref:reference:web/servlet.adoc#web.servlet.embedded-container.context-initializer.scanning[#features.developing-web-applications.embedded-container.context-initializer.scanning] * xref:reference:web/servlet.adoc#web.servlet.embedded-container.context-initializer.scanning[#web.servlet.embedded-container.context-initializer.scanning] -* xref:reference:web/servlet.adoc#web.servlet.embedded-container.customizing[#boot-features-customizing-embedded-containers] -* xref:reference:web/servlet.adoc#web.servlet.embedded-container.customizing[#web.servlet.embedded-container.customizing] +* xref:reference:web/servlet.adoc#web.servlet.embedded-container.context-initializer[#boot-features-embedded-container-context-initializer] +* xref:reference:web/servlet.adoc#web.servlet.embedded-container.context-initializer[#features.developing-web-applications.embedded-container.context-initializer] +* xref:reference:web/servlet.adoc#web.servlet.embedded-container.context-initializer[#web.servlet.embedded-container.context-initializer] * xref:reference:web/servlet.adoc#web.servlet.embedded-container.customizing.direct[#boot-features-customizing-configurableservletwebserverfactory-directly] +* xref:reference:web/servlet.adoc#web.servlet.embedded-container.customizing.direct[#features.developing-web-applications.embedded-container.customizing.direct] * xref:reference:web/servlet.adoc#web.servlet.embedded-container.customizing.direct[#web.servlet.embedded-container.customizing.direct] * xref:reference:web/servlet.adoc#web.servlet.embedded-container.customizing.encoding[#web.servlet.embedded-container.customizing.encoding] * xref:reference:web/servlet.adoc#web.servlet.embedded-container.customizing.programmatic[#boot-features-programmatic-embedded-container-customization] +* xref:reference:web/servlet.adoc#web.servlet.embedded-container.customizing.programmatic[#features.developing-web-applications.embedded-container.customizing.programmatic] * xref:reference:web/servlet.adoc#web.servlet.embedded-container.customizing.programmatic[#web.servlet.embedded-container.customizing.programmatic] * xref:reference:web/servlet.adoc#web.servlet.embedded-container.customizing.samesite[#web.servlet.embedded-container.customizing.samesite] -* xref:reference:web/servlet.adoc#web.servlet.embedded-container.jsp-limitations[#web.servlet.embedded-container.jsp-limitations] +* xref:reference:web/servlet.adoc#web.servlet.embedded-container.customizing[#boot-features-customizing-embedded-containers] +* xref:reference:web/servlet.adoc#web.servlet.embedded-container.customizing[#features.developing-web-applications.embedded-container.customizing] +* xref:reference:web/servlet.adoc#web.servlet.embedded-container.customizing[#web.servlet.embedded-container.customizing] * xref:reference:web/servlet.adoc#web.servlet.embedded-container.jsp-limitations[#boot-features-jsp-limitations] -* xref:reference:web/servlet.adoc#web.servlet.embedded-container.servlets-filters-listeners[#boot-features-embedded-container-servlets-filters-listeners] -* xref:reference:web/servlet.adoc#web.servlet.embedded-container.servlets-filters-listeners[#web.servlet.embedded-container.servlets-filters-listeners] +* xref:reference:web/servlet.adoc#web.servlet.embedded-container.jsp-limitations[#features.developing-web-applications.embedded-container.jsp-limitations] +* xref:reference:web/servlet.adoc#web.servlet.embedded-container.jsp-limitations[#web.servlet.embedded-container.jsp-limitations] * xref:reference:web/servlet.adoc#web.servlet.embedded-container.servlets-filters-listeners.beans[#boot-features-embedded-container-servlets-filters-listeners-beans] +* xref:reference:web/servlet.adoc#web.servlet.embedded-container.servlets-filters-listeners.beans[#features.developing-web-applications.embedded-container.servlets-filters-listeners.beans] * xref:reference:web/servlet.adoc#web.servlet.embedded-container.servlets-filters-listeners.beans[#web.servlet.embedded-container.servlets-filters-listeners.beans] -* xref:reference:web/servlet.adoc#web.servlet.jersey[#web.servlet.jersey] +* xref:reference:web/servlet.adoc#web.servlet.embedded-container.servlets-filters-listeners[#boot-features-embedded-container-servlets-filters-listeners] +* xref:reference:web/servlet.adoc#web.servlet.embedded-container.servlets-filters-listeners[#features.developing-web-applications.embedded-container.servlets-filters-listeners] +* xref:reference:web/servlet.adoc#web.servlet.embedded-container.servlets-filters-listeners[#web.servlet.embedded-container.servlets-filters-listeners] +* xref:reference:web/servlet.adoc#web.servlet.embedded-container[#boot-features-embedded-container] +* xref:reference:web/servlet.adoc#web.servlet.embedded-container[#features.developing-web-applications.embedded-container] +* xref:reference:web/servlet.adoc#web.servlet.embedded-container[#web.servlet.embedded-container] * xref:reference:web/servlet.adoc#web.servlet.jersey[#boot-features-jersey] -* xref:reference:web/servlet.adoc#web.servlet.spring-mvc[#boot-features-spring-mvc] -* xref:reference:web/servlet.adoc#web.servlet.spring-mvc[#web.servlet.spring-mvc] -* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.auto-configuration[#web.servlet.spring-mvc.auto-configuration] +* xref:reference:web/servlet.adoc#web.servlet.jersey[#features.developing-web-applications.jersey] +* xref:reference:web/servlet.adoc#web.servlet.jersey[#web.servlet.jersey] * xref:reference:web/servlet.adoc#web.servlet.spring-mvc.auto-configuration[#boot-features-spring-mvc-auto-configuration] -* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.binding-initializer[#web.servlet.spring-mvc.binding-initializer] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.auto-configuration[#features.developing-web-applications.spring-mvc.auto-configuration] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.auto-configuration[#web.servlet.spring-mvc.auto-configuration] * xref:reference:web/servlet.adoc#web.servlet.spring-mvc.binding-initializer[#boot-features-spring-mvc-web-binding-initializer] -* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.content-negotiation[#web.servlet.spring-mvc.content-negotiation] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.binding-initializer[#features.developing-web-applications.spring-mvc.binding-initializer] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.binding-initializer[#web.servlet.spring-mvc.binding-initializer] * xref:reference:web/servlet.adoc#web.servlet.spring-mvc.content-negotiation[#boot-features-spring-mvc-pathmatch] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.content-negotiation[#features.developing-web-applications.spring-mvc.content-negotiation] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.content-negotiation[#web.servlet.spring-mvc.content-negotiation] * xref:reference:web/servlet.adoc#web.servlet.spring-mvc.conversion-service[#web.servlet.spring-mvc.conversion-service] -* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.cors[#web.servlet.spring-mvc.cors] * xref:reference:web/servlet.adoc#web.servlet.spring-mvc.cors[#boot-features-cors] -* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.error-handling[#web.servlet.spring-mvc.error-handling] -* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.error-handling[#boot-features-error-handling] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.cors[#features.developing-web-applications.spring-mvc.cors] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.cors[#web.servlet.spring-mvc.cors] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.error-handling.error-pages-without-spring-mvc[#boot-features-error-handling-mapping-error-pages-without-mvc] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.error-handling.error-pages-without-spring-mvc[#features.developing-web-applications.spring-mvc.error-handling.error-pages-without-spring-mvc] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.error-handling.error-pages-without-spring-mvc[#web.servlet.spring-mvc.error-handling.error-pages-without-spring-mvc] * xref:reference:web/servlet.adoc#web.servlet.spring-mvc.error-handling.error-pages[#boot-features-error-handling-custom-error-pages] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.error-handling.error-pages[#features.developing-web-applications.spring-mvc.error-handling.error-pages] * xref:reference:web/servlet.adoc#web.servlet.spring-mvc.error-handling.error-pages[#web.servlet.spring-mvc.error-handling.error-pages] -* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.error-handling.error-pages-without-spring-mvc[#web.servlet.spring-mvc.error-handling.error-pages-without-spring-mvc] -* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.error-handling.error-pages-without-spring-mvc[#boot-features-error-handling-mapping-error-pages-without-mvc] -* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.error-handling.in-a-war-deployment[#web.servlet.spring-mvc.error-handling.in-a-war-deployment] * xref:reference:web/servlet.adoc#web.servlet.spring-mvc.error-handling.in-a-war-deployment[#boot-features-error-handling-war-deployment] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.error-handling.in-a-war-deployment[#features.developing-web-applications.spring-mvc.error-handling.in-a-war-deployment] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.error-handling.in-a-war-deployment[#web.servlet.spring-mvc.error-handling.in-a-war-deployment] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.error-handling[#boot-features-error-handling] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.error-handling[#features.developing-web-applications.spring-mvc.error-handling] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.error-handling[#web.servlet.spring-mvc.error-handling] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.favicon[#features.developing-web-applications.spring-mvc.favicon] * xref:reference:web/servlet.adoc#web.servlet.spring-mvc.favicon[#web.servlet.spring-mvc.favicon] -* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.message-codes[#web.servlet.spring-mvc.message-codes] * xref:reference:web/servlet.adoc#web.servlet.spring-mvc.message-codes[#boot-features-spring-message-codes] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.message-codes[#features.developing-web-applications.spring-mvc.message-codes] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.message-codes[#web.servlet.spring-mvc.message-codes] * xref:reference:web/servlet.adoc#web.servlet.spring-mvc.message-converters[#boot-features-spring-mvc-message-converters] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.message-converters[#features.developing-web-applications.spring-mvc.message-converters] * xref:reference:web/servlet.adoc#web.servlet.spring-mvc.message-converters[#web.servlet.spring-mvc.message-converters] * xref:reference:web/servlet.adoc#web.servlet.spring-mvc.static-content[#boot-features-spring-mvc-static-content] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.static-content[#features.developing-web-applications.spring-mvc.static-content] * xref:reference:web/servlet.adoc#web.servlet.spring-mvc.static-content[#web.servlet.spring-mvc.static-content] * xref:reference:web/servlet.adoc#web.servlet.spring-mvc.template-engines[#boot-features-spring-mvc-template-engines] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.template-engines[#features.developing-web-applications.spring-mvc.template-engines] * xref:reference:web/servlet.adoc#web.servlet.spring-mvc.template-engines[#web.servlet.spring-mvc.template-engines] -* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.welcome-page[#web.servlet.spring-mvc.welcome-page] * xref:reference:web/servlet.adoc#web.servlet.spring-mvc.welcome-page[#boot-features-spring-mvc-welcome-page] -* xref:reference:web/spring-graphql.adoc#web.graphql[#web.graphql] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.welcome-page[#features.developing-web-applications.spring-mvc.welcome-page] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.welcome-page[#web.servlet.spring-mvc.welcome-page] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc[#boot-features-spring-mvc] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc[#features.developing-web-applications.spring-mvc] +* xref:reference:web/servlet.adoc#web.servlet.spring-mvc[#web.servlet.spring-mvc] +* xref:reference:web/servlet.adoc#web.servlet[#web.servlet] * xref:reference:web/spring-graphql.adoc#web.graphql.data-query[#web.graphql.data-query] * xref:reference:web/spring-graphql.adoc#web.graphql.exception-handling[#web.graphql.exception-handling] * xref:reference:web/spring-graphql.adoc#web.graphql.graphiql[#web.graphql.graphiql] * xref:reference:web/spring-graphql.adoc#web.graphql.runtimewiring[#web.graphql.runtimewiring] * xref:reference:web/spring-graphql.adoc#web.graphql.schema[#web.graphql.schema] -* xref:reference:web/spring-graphql.adoc#web.graphql.transports[#web.graphql.transports] * xref:reference:web/spring-graphql.adoc#web.graphql.transports.http-websocket[#web.graphql.transports.http-websocket] * xref:reference:web/spring-graphql.adoc#web.graphql.transports.rsocket[#web.graphql.transports.rsocket] +* xref:reference:web/spring-graphql.adoc#web.graphql.transports[#web.graphql.transports] +* xref:reference:web/spring-graphql.adoc#web.graphql[#web.graphql] * xref:reference:web/spring-hateoas.adoc#web.spring-hateoas[#boot-features-spring-hateoas] +* xref:reference:web/spring-hateoas.adoc#web.spring-hateoas[#features.spring-hateoas] * xref:reference:web/spring-hateoas.adoc#web.spring-hateoas[#web.spring-hateoas] -* xref:reference:web/spring-security.adoc#web.security[#boot-features-security] -* xref:reference:web/spring-security.adoc#web.security[#web.security] -* xref:reference:web/spring-security.adoc#web.security.oauth2[#web.security.oauth2] -* xref:reference:web/spring-security.adoc#web.security.oauth2[#boot-features-security-oauth2] -* xref:reference:web/spring-security.adoc#web.security.oauth2.authorization-server[#web.security.oauth2.authorization-server] * xref:reference:web/spring-security.adoc#web.security.oauth2.authorization-server[#boot-features-security-authorization-server] -* xref:reference:web/spring-security.adoc#web.security.oauth2.client[#boot-features-security-oauth2-client] -* xref:reference:web/spring-security.adoc#web.security.oauth2.client[#web.security.oauth2.client] +* xref:reference:web/spring-security.adoc#web.security.oauth2.authorization-server[#features.security.authorization-server] +* xref:reference:web/spring-security.adoc#web.security.oauth2.authorization-server[#web.security.oauth2.authorization-server] * xref:reference:web/spring-security.adoc#web.security.oauth2.client.common-providers[#boot-features-security-oauth2-common-providers] +* xref:reference:web/spring-security.adoc#web.security.oauth2.client.common-providers[#features.security.oauth2.client.common-providers] * xref:reference:web/spring-security.adoc#web.security.oauth2.client.common-providers[#web.security.oauth2.client.common-providers] -* xref:reference:web/spring-security.adoc#web.security.oauth2.server[#web.security.oauth2.server] +* xref:reference:web/spring-security.adoc#web.security.oauth2.client[#boot-features-security-oauth2-client] +* xref:reference:web/spring-security.adoc#web.security.oauth2.client[#features.security.oauth2.client] +* xref:reference:web/spring-security.adoc#web.security.oauth2.client[#web.security.oauth2.client] * xref:reference:web/spring-security.adoc#web.security.oauth2.server[#boot-features-security-oauth2-server] +* xref:reference:web/spring-security.adoc#web.security.oauth2.server[#features.security.oauth2.server] +* xref:reference:web/spring-security.adoc#web.security.oauth2.server[#web.security.oauth2.server] +* xref:reference:web/spring-security.adoc#web.security.oauth2[#boot-features-security-oauth2] +* xref:reference:web/spring-security.adoc#web.security.oauth2[#features.security.oauth2] +* xref:reference:web/spring-security.adoc#web.security.oauth2[#web.security.oauth2] +* xref:reference:web/spring-security.adoc#web.security.saml2.relying-party[#boot-features-security-saml2-relying-party] +* xref:reference:web/spring-security.adoc#web.security.saml2.relying-party[#features.security.saml2.relying-party] +* xref:reference:web/spring-security.adoc#web.security.saml2.relying-party[#web.security.saml2.relying-party] * xref:reference:web/spring-security.adoc#web.security.saml2[#boot-features-security-saml] +* xref:reference:web/spring-security.adoc#web.security.saml2[#features.security.saml2] * xref:reference:web/spring-security.adoc#web.security.saml2[#web.security.saml2] -* xref:reference:web/spring-security.adoc#web.security.saml2.relying-party[#web.security.saml2.relying-party] -* xref:reference:web/spring-security.adoc#web.security.saml2.relying-party[#boot-features-security-saml2-relying-party] * xref:reference:web/spring-security.adoc#web.security.spring-mvc[#boot-features-security-mvc] +* xref:reference:web/spring-security.adoc#web.security.spring-mvc[#features.security.spring-mvc] * xref:reference:web/spring-security.adoc#web.security.spring-mvc[#web.security.spring-mvc] -* xref:reference:web/spring-security.adoc#web.security.spring-webflux[#web.security.spring-webflux] * xref:reference:web/spring-security.adoc#web.security.spring-webflux[#boot-features-security-webflux] +* xref:reference:web/spring-security.adoc#web.security.spring-webflux[#features.security.spring-webflux] +* xref:reference:web/spring-security.adoc#web.security.spring-webflux[#web.security.spring-webflux] +* xref:reference:web/spring-security.adoc#web.security[#boot-features-security] +* xref:reference:web/spring-security.adoc#web.security[#features.security] +* xref:reference:web/spring-security.adoc#web.security[#web.security] * xref:reference:web/spring-session.adoc#web.spring-session[#boot-features-session] +* xref:reference:web/spring-session.adoc#web.spring-session[#features.spring-session] * xref:reference:web/spring-session.adoc#web.spring-session[#web.spring-session] -* xref:specification:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor[#appendix.configuration-metadata.annotation-processor] * xref:specification:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.adding-additional-metadata[#appendix.configuration-metadata.annotation-processor.adding-additional-metadata] -* xref:specification:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.automatic-metadata-generation[#appendix.configuration-metadata.annotation-processor.automatic-metadata-generation] +* xref:specification:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.adding-additional-metadata[#configuration-metadata.annotation-processor.adding-additional-metadata] * xref:specification:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.automatic-metadata-generation.nested-properties[#appendix.configuration-metadata.annotation-processor.automatic-metadata-generation.nested-properties] +* xref:specification:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.automatic-metadata-generation.nested-properties[#configuration-metadata.annotation-processor.automatic-metadata-generation.nested-properties] +* xref:specification:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.automatic-metadata-generation[#appendix.configuration-metadata.annotation-processor.automatic-metadata-generation] +* xref:specification:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.automatic-metadata-generation[#configuration-metadata.annotation-processor.automatic-metadata-generation] * xref:specification:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.configuring[#appendix.configuration-metadata.annotation-processor.configuring] -* xref:specification:configuration-metadata/format.adoc#appendix.configuration-metadata.format[#appendix.configuration-metadata.format] +* xref:specification:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.configuring[#configuration-metadata.annotation-processor.configuring] +* xref:specification:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor[#appendix.configuration-metadata.annotation-processor] +* xref:specification:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor[#configuration-metadata.annotation-processor] * xref:specification:configuration-metadata/format.adoc#appendix.configuration-metadata.format.group[#appendix.configuration-metadata.format.group] +* xref:specification:configuration-metadata/format.adoc#appendix.configuration-metadata.format.group[#configuration-metadata.format.group] * xref:specification:configuration-metadata/format.adoc#appendix.configuration-metadata.format.hints[#appendix.configuration-metadata.format.hints] +* xref:specification:configuration-metadata/format.adoc#appendix.configuration-metadata.format.hints[#configuration-metadata.format.hints] * xref:specification:configuration-metadata/format.adoc#appendix.configuration-metadata.format.property[#appendix.configuration-metadata.format.property] +* xref:specification:configuration-metadata/format.adoc#appendix.configuration-metadata.format.property[#configuration-metadata.format.property] * xref:specification:configuration-metadata/format.adoc#appendix.configuration-metadata.format.repeated-items[#appendix.configuration-metadata.format.repeated-items] +* xref:specification:configuration-metadata/format.adoc#appendix.configuration-metadata.format.repeated-items[#configuration-metadata.format.repeated-items] +* xref:specification:configuration-metadata/format.adoc#appendix.configuration-metadata.format[#appendix.configuration-metadata.format] +* xref:specification:configuration-metadata/format.adoc#appendix.configuration-metadata.format[#configuration-metadata.format] * xref:specification:configuration-metadata/index.adoc#appendix.configuration-metadata[#appendix.configuration-metadata] -* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints[#appendix.configuration-metadata.manual-hints] +* xref:specification:configuration-metadata/index.adoc#appendix.configuration-metadata[#configuration-metadata] +* xref:specification:configuration-metadata/index.adoc[#configuration-metadata] +* xref:specification:configuration-metadata/index.adoc[configuration-metadata] * xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-hint[#appendix.configuration-metadata.manual-hints.value-hint] -* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers[#appendix.configuration-metadata.manual-hints.value-providers] +* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-hint[#configuration-metadata.manual-hints.value-hint] * xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers.any[#appendix.configuration-metadata.manual-hints.value-providers.any] +* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers.any[#configuration-metadata.manual-hints.value-providers.any] * xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers.class-reference[#appendix.configuration-metadata.manual-hints.value-providers.class-reference] +* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers.class-reference[#configuration-metadata.manual-hints.value-providers.class-reference] * xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers.handle-as[#appendix.configuration-metadata.manual-hints.value-providers.handle-as] +* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers.handle-as[#configuration-metadata.manual-hints.value-providers.handle-as] * xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers.logger-name[#appendix.configuration-metadata.manual-hints.value-providers.logger-name] +* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers.logger-name[#configuration-metadata.manual-hints.value-providers.logger-name] * xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers.spring-bean-reference[#appendix.configuration-metadata.manual-hints.value-providers.spring-bean-reference] +* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers.spring-bean-reference[#configuration-metadata.manual-hints.value-providers.spring-bean-reference] * xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers.spring-profile-name[#appendix.configuration-metadata.manual-hints.value-providers.spring-profile-name] +* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers.spring-profile-name[#configuration-metadata.manual-hints.value-providers.spring-profile-name] +* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers[#appendix.configuration-metadata.manual-hints.value-providers] +* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers[#configuration-metadata.manual-hints.value-providers] +* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints[#appendix.configuration-metadata.manual-hints] +* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints[#configuration-metadata.manual-hints] * xref:specification:executable-jar/alternatives.adoc#appendix.executable-jar.alternatives[#appendix.executable-jar.alternatives] +* xref:specification:executable-jar/alternatives.adoc#appendix.executable-jar.alternatives[#executable-jar.alternatives] * xref:specification:executable-jar/index.adoc#appendix.executable-jar[#appendix.executable-jar] -* xref:specification:executable-jar/jarfile-class.adoc#appendix.executable-jar.jarfile-class[#appendix.executable-jar.jarfile-class] +* xref:specification:executable-jar/index.adoc#appendix.executable-jar[#executable-jar] +* xref:specification:executable-jar/index.adoc[#executable-jar] +* xref:specification:executable-jar/index.adoc[executable-jar] * xref:specification:executable-jar/jarfile-class.adoc#appendix.executable-jar.jarfile-class.compatibility[#appendix.executable-jar.jarfile-class.compatibility] -* xref:specification:executable-jar/launching.adoc#appendix.executable-jar.launching[#appendix.executable-jar.launching] +* xref:specification:executable-jar/jarfile-class.adoc#appendix.executable-jar.jarfile-class.compatibility[#executable-jar.jarfile-class.compatibility] +* xref:specification:executable-jar/jarfile-class.adoc#appendix.executable-jar.jarfile-class[#appendix.executable-jar.jarfile-class] +* xref:specification:executable-jar/jarfile-class.adoc#appendix.executable-jar.jarfile-class[#executable-jar.jarfile-class] * xref:specification:executable-jar/launching.adoc#appendix.executable-jar.launching.manifest[#appendix.executable-jar.launching.manifest] -* xref:specification:executable-jar/nested-jars.adoc#appendix.executable-jar.nested-jars[#appendix.executable-jar.nested-jars] +* xref:specification:executable-jar/launching.adoc#appendix.executable-jar.launching.manifest[#executable-jar.launching.manifest] +* xref:specification:executable-jar/launching.adoc#appendix.executable-jar.launching[#appendix.executable-jar.launching] +* xref:specification:executable-jar/launching.adoc#appendix.executable-jar.launching[#executable-jar.launching] * xref:specification:executable-jar/nested-jars.adoc#appendix.executable-jar.nested-jars.classpath-index[#appendix.executable-jar.nested-jars.classpath-index] +* xref:specification:executable-jar/nested-jars.adoc#appendix.executable-jar.nested-jars.classpath-index[#executable-jar.nested-jars.classpath-index] * xref:specification:executable-jar/nested-jars.adoc#appendix.executable-jar.nested-jars.index-files[#appendix.executable-jar.nested-jars.index-files] +* xref:specification:executable-jar/nested-jars.adoc#appendix.executable-jar.nested-jars.index-files[#executable-jar.nested-jars.index-files] * xref:specification:executable-jar/nested-jars.adoc#appendix.executable-jar.nested-jars.jar-structure[#appendix.executable-jar.nested-jars.jar-structure] +* xref:specification:executable-jar/nested-jars.adoc#appendix.executable-jar.nested-jars.jar-structure[#executable-jar.nested-jars.jar-structure] * xref:specification:executable-jar/nested-jars.adoc#appendix.executable-jar.nested-jars.layer-index[#appendix.executable-jar.nested-jars.layer-index] +* xref:specification:executable-jar/nested-jars.adoc#appendix.executable-jar.nested-jars.layer-index[#executable-jar.nested-jars.layer-index] * xref:specification:executable-jar/nested-jars.adoc#appendix.executable-jar.nested-jars.war-structure[#appendix.executable-jar.nested-jars.war-structure] +* xref:specification:executable-jar/nested-jars.adoc#appendix.executable-jar.nested-jars.war-structure[#executable-jar.nested-jars.war-structure] +* xref:specification:executable-jar/nested-jars.adoc#appendix.executable-jar.nested-jars[#appendix.executable-jar.nested-jars] +* xref:specification:executable-jar/nested-jars.adoc#appendix.executable-jar.nested-jars[#executable-jar.nested-jars] * xref:specification:executable-jar/property-launcher.adoc#appendix.executable-jar.property-launcher[#appendix.executable-jar.property-launcher] +* xref:specification:executable-jar/property-launcher.adoc#appendix.executable-jar.property-launcher[#executable-jar.property-launcher] * xref:specification:executable-jar/restrictions.adoc#appendix.executable-jar-system-classloader[#appendix.executable-jar-system-classloader] * xref:specification:executable-jar/restrictions.adoc#appendix.executable-jar-zip-entry-compression[#appendix.executable-jar-zip-entry-compression] * xref:specification:executable-jar/restrictions.adoc#appendix.executable-jar.restrictions[#appendix.executable-jar.restrictions] -* xref:tutorial:first-application/index.adoc#getting-started.first-application[#getting-started.first-application] -* xref:tutorial:first-application/index.adoc#getting-started.first-application.code[#getting-started.first-application.code] +* xref:specification:executable-jar/restrictions.adoc#appendix.executable-jar.restrictions[#executable-jar.restrictions] +* xref:tutorial:first-application/index.adoc#getting-started.first-application.code.main-method[#getting-started-first-application-main-method] * xref:tutorial:first-application/index.adoc#getting-started.first-application.code.main-method[#getting-started.first-application.code.main-method] +* xref:tutorial:first-application/index.adoc#getting-started.first-application.code.mvc-annotations[#getting-started-first-application-annotations] * xref:tutorial:first-application/index.adoc#getting-started.first-application.code.mvc-annotations[#getting-started.first-application.code.mvc-annotations] * xref:tutorial:first-application/index.adoc#getting-started.first-application.code.spring-boot-application[#getting-started-first-application-auto-configuration] +* xref:tutorial:first-application/index.adoc#getting-started.first-application.code.spring-boot-application[#getting-started.first-application.code.enable-auto-configuration] * xref:tutorial:first-application/index.adoc#getting-started.first-application.code.spring-boot-application[#getting-started.first-application.code.spring-boot-application] -* xref:tutorial:first-application/index.adoc#getting-started.first-application.dependencies[#getting-started.first-application.dependencies] +* xref:tutorial:first-application/index.adoc#getting-started.first-application.code[#getting-started-first-application-code] +* xref:tutorial:first-application/index.adoc#getting-started.first-application.code[#getting-started.first-application.code] * xref:tutorial:first-application/index.adoc#getting-started.first-application.dependencies.gradle[#getting-started.first-application.dependencies.gradle] * xref:tutorial:first-application/index.adoc#getting-started.first-application.dependencies.maven[#getting-started.first-application.dependencies.maven] -* xref:tutorial:first-application/index.adoc#getting-started.first-application.executable-jar[#getting-started.first-application.executable-jar] +* xref:tutorial:first-application/index.adoc#getting-started.first-application.dependencies[#getting-started-first-application-dependencies] +* xref:tutorial:first-application/index.adoc#getting-started.first-application.dependencies[#getting-started.first-application.dependencies] * xref:tutorial:first-application/index.adoc#getting-started.first-application.executable-jar.gradle[#getting-started.first-application.executable-jar.gradle] * xref:tutorial:first-application/index.adoc#getting-started.first-application.executable-jar.maven[#getting-started.first-application.executable-jar.maven] +* xref:tutorial:first-application/index.adoc#getting-started.first-application.executable-jar[#getting-started-first-application-executable-jar] +* xref:tutorial:first-application/index.adoc#getting-started.first-application.executable-jar[#getting-started.first-application.executable-jar] * xref:tutorial:first-application/index.adoc#getting-started.first-application.gradle[#getting-started.first-application.gradle] +* xref:tutorial:first-application/index.adoc#getting-started.first-application.pom[#getting-started-first-application-pom] * xref:tutorial:first-application/index.adoc#getting-started.first-application.pom[#getting-started.first-application.pom] -* xref:tutorial:first-application/index.adoc#getting-started.first-application.prerequisites[#getting-started.first-application.prerequisites] * xref:tutorial:first-application/index.adoc#getting-started.first-application.prerequisites.gradle[#getting-started.first-application.prerequisites.gradle] * xref:tutorial:first-application/index.adoc#getting-started.first-application.prerequisites.maven[#getting-started.first-application.prerequisites.maven] -* xref:tutorial:first-application/index.adoc#getting-started.first-application.run[#getting-started.first-application.run] +* xref:tutorial:first-application/index.adoc#getting-started.first-application.prerequisites[#getting-started.first-application.prerequisites] * xref:tutorial:first-application/index.adoc#getting-started.first-application.run.gradle[#getting-started.first-application.run.gradle] * xref:tutorial:first-application/index.adoc#getting-started.first-application.run.maven[#getting-started.first-application.run.maven] -* xref:reference:io/caching.adoc#io.caching.provider.jcache[#features.caching.provider.ehcache2] -* xref:reference:features/external-config.adoc#features.external-config.files.importing-extensionless[#features.external-config.file.importing-extensionless] -* xref:reference:using/build-systems.adoc#using.build-systems.maven[#build-tool-plugins.maven] -* xref:reference:using/build-systems.adoc#using.build-systems.gradle[#build-tool-plugins.gradle] -* xref:reference:messaging/amqp.adoc#messaging.amqp.rabbitmq[#messaging.amqp.rabbit] -* xref:reference:data/nosql.adoc#data.nosql.elasticsearch.connecting-using-rest[#data.nosql.elasticsearch.connecting-using-reactive-rest] -* xref:index.adoc[#getting-started.introducing-spring-boot] -* xref:index.adoc[#spring-boot-reference-documentation] -* xref:appendix:application-properties/index.adoc#appendix.application-properties.actuator[#common-application-properties-actuator] -* xref:reference:actuator/http-exchanges.adoc#actuator.http-exchanges[#actuator.tracing] -* xref:reference:actuator/http-exchanges.adoc#actuator.http-exchanges.custom[#actuator.tracing.custom] -* xref:appendix:application-properties/index.adoc#appendix.application-properties[#common-application-properties] -* xref:appendix:application-properties/index.adoc#appendix.application-properties.cache[#common-application-properties-cache] -* xref:appendix:application-properties/index.adoc#appendix.application-properties.core[#core-properties] -* xref:appendix:application-properties/index.adoc#appendix.application-properties.data[#data-properties] -* xref:appendix:application-properties/index.adoc#appendix.application-properties.data-migration[#data-migration-properties] -* xref:appendix:application-properties/index.adoc#appendix.application-properties.devtools[#devtools-properties] -* xref:appendix:application-properties/index.adoc#appendix.application-properties.integration[#integration-properties] -* xref:appendix:application-properties/index.adoc#appendix.application-properties.json[#json-properties] -* xref:appendix:application-properties/index.adoc#appendix.application-properties.mail[#mail-properties] -* xref:appendix:application-properties/index.adoc#appendix.application-properties.rsocket[#rsocket-properties] -* xref:appendix:application-properties/index.adoc#appendix.application-properties.security[#security-properties] -* xref:appendix:application-properties/index.adoc#appendix.application-properties.server[#server-properties] -* xref:appendix:application-properties/index.adoc#appendix.application-properties.templating[#templating-properties] -* xref:appendix:application-properties/index.adoc#appendix.application-properties.testing[#testing-properties] -* xref:appendix:application-properties/index.adoc#appendix.application-properties.transaction[#transaction-properties] -* xref:appendix:application-properties/index.adoc#appendix.application-properties.web[#web-properties] -* xref:appendix:auto-configuration-classes/index.adoc#appendix.auto-configuration-classes[#auto-configuration-classes] -* xref:appendix:auto-configuration-classes/actuator.adoc#appendix.auto-configuration-classes.actuator[#auto-configuration-classes.actuator] -* xref:appendix:auto-configuration-classes/core.adoc#appendix.auto-configuration-classes.core[#auto-configuration-classes.core] -* xref:ROOT:documentation.adoc#documentation[#boot-documentation] -* xref:documentation.adoc[#boot-documentation-about] -* xref:ROOT:documentation.adoc#documentation.advanced[#boot-documentation-advanced] -* xref:ROOT:documentation.adoc#documentation.first-steps[#boot-documentation-first-steps] -* xref:community.adoc[#boot-documentation-getting-help] -* xref:ROOT:documentation.adoc#documentation.features[#boot-documentation-learning] -* xref:ROOT:documentation.adoc#documentation.actuator[#boot-documentation-production] -* xref:ROOT:documentation.adoc#documentation.upgrading[#boot-documentation-upgrading] -* xref:ROOT:documentation.adoc#documentation.using[#boot-documentation-workingwith] -* xref:reference:features/index.adoc#features[#boot-features] -* xref:reference:messaging/jms.adoc#messaging.jms.activemq[#features.messaging.jms.activemq] -* xref:reference:features/profiles.adoc#features.profiles.adding-active-profiles[#boot-features-adding-active-profiles] -* xref:reference:messaging/amqp.adoc#messaging.amqp[#features.messaging.amqp] -* xref:reference:features/spring-application.adoc#features.spring-application.admin[#boot-features-application-admin] -* xref:reference:features/spring-application.adoc#features.spring-application.application-arguments[#boot-features-application-arguments] -* xref:reference:features/spring-application.adoc#features.spring-application.application-availability[#boot-features-application-availability] -* xref:reference:features/spring-application.adoc#features.spring-application.application-availability.liveness[#boot-features-application-availability-liveness-state] -* xref:reference:features/spring-application.adoc#features.spring-application.application-availability.managing[#boot-features-application-availability-managing] -* xref:reference:features/spring-application.adoc#features.spring-application.application-availability.readiness[#boot-features-application-availability-readiness-state] -* xref:reference:features/spring-application.adoc#features.spring-application.application-events-and-listeners[#boot-features-application-events-and-listeners] -* xref:reference:features/spring-application.adoc#features.spring-application.application-exit[#boot-features-application-exit] -* xref:reference:features/spring-application.adoc#features.spring-application.startup-tracking[#boot-features-application-startup-tracking] -* xref:reference:messaging/jms.adoc#messaging.jms.artemis[#features.messaging.jms.artemis] -* xref:reference:features/spring-application.adoc#features.spring-application.banner[#boot-features-banner] -* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.bean-conditions[#boot-features-bean-conditions] -* xref:reference:io/caching.adoc#io.caching[#features.caching] -* xref:reference:io/caching.adoc#io.caching.provider[#features.caching.provider] -* xref:reference:io/caching.adoc#io.caching.provider.caffeine[#features.caching.provider.caffeine] -* xref:reference:io/caching.adoc#io.caching.provider.couchbase[#features.caching.provider.couchbase] -* xref:reference:io/caching.adoc#io.caching.provider.jcache[#features.caching.provider.jcache] -* xref:reference:io/caching.adoc#io.caching.provider.generic[#features.caching.provider.generic] -* xref:reference:io/caching.adoc#io.caching.provider.hazelcast[#features.caching.provider.hazelcast] -* xref:reference:io/caching.adoc#io.caching.provider.infinispan[#features.caching.provider.infinispan] -* xref:reference:io/caching.adoc#io.caching.provider.none[#features.caching.provider.none] -* xref:reference:io/caching.adoc#io.caching.provider.redis[#features.caching.provider.redis] -* xref:reference:io/caching.adoc#io.caching.provider.simple[#features.caching.provider.simple] -* xref:reference:data/nosql.adoc#data.nosql.cassandra[#features.nosql.cassandra] -* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.class-conditions[#boot-features-class-conditions] -* xref:reference:features/spring-application.adoc#features.spring-application.command-line-runner[#boot-features-command-line-runner] -* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations[#boot-features-condition-annotations] -* xref:reference:testing/test-utilities.adoc#testing.utilities.config-data-application-context-initializer[#boot-features-configfileapplicationcontextinitializer-test-utility] -* xref:reference:data/sql.adoc#data.sql.datasource[#features.sql.datasource] -* xref:reference:data/sql.adoc#data.sql.datasource.production[#features.sql.datasource.production] -* xref:reference:data/sql.adoc#data.sql.datasource.configuration[#features.sql.datasource.configuration] -* xref:reference:data/sql.adoc#data.sql.datasource.connection-pool[#features.sql.datasource.connection-pool] -* xref:reference:data/sql.adoc#data.sql.datasource.jndi[#features.sql.datasource.jndi] -* xref:reference:data/nosql.adoc#data.nosql.cassandra.connecting[#features.nosql.cassandra.connecting] -* xref:reference:data/nosql.adoc#data.nosql.couchbase.connecting[#features.nosql.couchbase.connecting] -* xref:reference:data/nosql.adoc#data.nosql.elasticsearch[#features.nosql.elasticsearch] -* xref:reference:data/nosql.adoc#data.nosql.elasticsearch.connecting-using-rest[#features.nosql.elasticsearch.connecting-using-rest] -* xref:reference:data/nosql.adoc#data.nosql.elasticsearch.connecting-using-spring-data[#features.nosql.elasticsearch.connecting-using-spring-data] -* xref:reference:data/nosql.adoc#data.nosql.influxdb.connecting[#features.nosql.influxdb.connecting] -* xref:reference:data/nosql.adoc#data.nosql.mongodb.connecting[#features.nosql.mongodb.connecting] -* xref:reference:data/nosql.adoc#data.nosql.neo4j.connecting[#features.nosql.neo4j.connecting] -* xref:reference:data/nosql.adoc#data.nosql.redis.connecting[#features.nosql.redis.connecting] -* xref:reference:packaging/container-images/efficient-images.adoc#packaging.container-images.efficient-images[#features.container-images.building] -* xref:reference:packaging/container-images/cloud-native-buildpacks.adoc#packaging.container-images.buildpacks[#features.container-images.building.buildpacks] -* xref:reference:packaging/container-images/dockerfiles.adoc#packaging.container-images.dockerfiles[#features.container-images.building.dockerfiles] -* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.cors[#features.developing-web-applications.spring-mvc.cors] -* xref:reference:data/nosql.adoc#data.nosql.couchbase[#features.nosql.couchbase] -* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.creating-and-dropping[#features.sql.jpa-and-spring-data.creating-and-dropping] -* xref:reference:features/logging.adoc#features.logging.custom-log-configuration[#boot-features-custom-log-configuration] -* xref:reference:features/logging.adoc#features.logging.log-groups[#boot-features-custom-log-groups] -* xref:reference:features/logging.adoc#features.logging.log-levels[#boot-features-custom-log-levels] -* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.custom-starter[#boot-features-custom-starter] -* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.custom-starter.configuration-keys[#boot-features-custom-starter-configuration-keys] -* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.custom-starter.autoconfigure-module[#boot-features-custom-starter-module-autoconfigure] -* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.custom-starter.starter-module[#boot-features-custom-starter-module-starter] -* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.custom-starter.naming[#boot-features-custom-starter-naming] -* xref:reference:web/servlet.adoc#web.servlet.embedded-container.customizing.direct[#features.developing-web-applications.embedded-container.customizing.direct] -* xref:reference:web/servlet.adoc#web.servlet.embedded-container.customizing[#features.developing-web-applications.embedded-container.customizing] -* xref:reference:features/spring-application.adoc#features.spring-application.customizing-spring-application[#boot-features-customizing-spring-application] -* xref:reference:data/sql.adoc#data.sql.jdbc[#features.sql.jdbc] -* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration[#boot-features-developing-auto-configuration] -* xref:reference:web/index.adoc#web[#features.developing-web-applications] -* xref:reference:io/email.adoc#io.email[#features.email] -* xref:reference:web/servlet.adoc#web.servlet.embedded-container[#features.developing-web-applications.embedded-container] -* xref:reference:web/servlet.adoc#web.servlet.embedded-container.application-context[#features.developing-web-applications.embedded-container.application-context] -* xref:reference:web/servlet.adoc#web.servlet.embedded-container.context-initializer[#features.developing-web-applications.embedded-container.context-initializer] -* xref:reference:web/servlet.adoc#web.servlet.embedded-container.servlets-filters-listeners[#features.developing-web-applications.embedded-container.servlets-filters-listeners] -* xref:reference:web/servlet.adoc#web.servlet.embedded-container.servlets-filters-listeners.beans[#features.developing-web-applications.embedded-container.servlets-filters-listeners.beans] -* xref:reference:web/servlet.adoc#web.servlet.embedded-container.context-initializer.scanning[#features.developing-web-applications.embedded-container.context-initializer.scanning] -* xref:reference:data/sql.adoc#data.sql.datasource.embedded[#features.sql.datasource.embedded] -* xref:reference:messaging/kafka.adoc#messaging.kafka.embedded[#features.messaging.kafka.embedded] -* xref:reference:features/external-config.adoc#features.external-config.encrypting[#boot-features-encrypting-properties] -* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.entity-classes[#features.sql.jpa-and-spring-data.entity-classes] -* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.error-handling[#features.developing-web-applications.spring-mvc.error-handling] -* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.error-handling.error-pages[#features.developing-web-applications.spring-mvc.error-handling.error-pages] -* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.error-handling.error-pages-without-spring-mvc[#features.developing-web-applications.spring-mvc.error-handling.error-pages-without-spring-mvc] -* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.error-handling.in-a-war-deployment[#features.developing-web-applications.spring-mvc.error-handling.in-a-war-deployment] -* xref:reference:features/external-config.adoc#features.external-config[#boot-features-external-config] -* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.third-party-configuration[#boot-features-external-config-3rd-party-configuration] -* xref:reference:features/external-config.adoc#features.external-config.application-json[#boot-features-external-config-application-json] -* xref:reference:features/external-config.adoc#features.external-config.files[#boot-features-external-config-files] -* xref:reference:features/external-config.adoc#features.external-config.command-line-args[#boot-features-external-config-command-line-args] -* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.merging-complex-types[#boot-features-external-config-complex-type-merge] -* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.constructor-binding[#boot-features-external-config-constructor-binding] -* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.conversion[#boot-features-external-config-conversion] -* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.conversion.data-sizes[#boot-features-external-config-conversion-datasize] -* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.conversion.durations[#boot-features-external-config-conversion-duration] -* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.conversion.periods[#boot-features-external-config-conversion-period] -* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.enabling-annotated-types[#boot-features-external-config-enabling] -* xref:reference:features/external-config.adoc#features.external-config.yaml.directly-loading[#boot-features-external-config-loading-yaml] -* xref:reference:features/external-config.adoc#features.external-config.files.activation-properties[#boot-features-external-config-file-activation-properties] -* xref:reference:features/external-config.adoc#features.external-config.files.configtree[#boot-features-external-config-files-configtree] -* xref:reference:features/external-config.adoc#features.external-config.files.importing[#boot-features-external-config-files-importing] -* xref:reference:features/external-config.adoc#features.external-config.files.importing-extensionless[#boot-features-external-config-files-importing-extensionless] -* xref:reference:features/external-config.adoc#features.external-config.files.multi-document[#boot-features-external-config-files-multi-document] -* xref:reference:features/external-config.adoc#features.external-config.files.profile-specific[#boot-features-external-config-files-profile-specific] -* xref:reference:features/external-config.adoc#features.external-config.files.wildcard-locations[#boot-features-external-config-files-wildcards] -* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.java-bean-binding[#boot-features-external-config-java-bean-binding] -* xref:reference:features/external-config.adoc#features.external-config.files.optional-prefix[#boot-features-external-config-optional-prefix] -* xref:reference:features/external-config.adoc#features.external-config.files.property-placeholders[#boot-features-external-config-placeholders-in-properties] -* xref:reference:features/external-config.adoc#features.external-config.random-values[#boot-features-external-config-random-values] -* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.relaxed-binding[#boot-features-external-config-relaxed-binding] -* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.relaxed-binding.environment-variables[#boot-features-external-config-relaxed-binding-from-environment-variables] -* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.relaxed-binding.maps[#boot-features-external-config-relaxed-binding-maps] -* xref:reference:features/external-config.adoc#features.external-config.system-environment[#boot-features-external-config-system-environment] -* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties[#boot-features-external-config-typesafe-configuration-properties] -* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.using-annotated-types[#boot-features-external-config-using] -* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.validation[#boot-features-external-config-validation] -* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.vs-value-annotation[#boot-features-external-config-vs-value] -* xref:reference:features/external-config.adoc#features.external-config.yaml[#boot-features-external-config-yaml] -* xref:reference:features/external-config.adoc#features.external-config.yaml.mapping-to-properties[#boot-features-external-config-yaml-to-properties] -* xref:reference:features/spring-application.adoc#features.spring-application.fluent-builder-api[#boot-features-fluent-builder-api] -* xref:reference:web/graceful-shutdown.adoc#web.graceful-shutdown[#features.graceful-shutdown] -* xref:reference:io/hazelcast.adoc#io.hazelcast[#features.hazelcast] -* xref:reference:data/nosql.adoc#data.nosql.influxdb[#features.nosql.influxdb] -* xref:reference:messaging/spring-integration.adoc#messaging.spring-integration[#features.spring-integration] -* xref:reference:features/internationalization.adoc#features.internationalization[#boot-features-internationalization] -* xref:reference:web/servlet.adoc#web.servlet.jersey[#features.developing-web-applications.jersey] -* xref:reference:messaging/jms.adoc#messaging.jms[#features.messaging.jms] -* xref:reference:messaging/jms.adoc#messaging.jms.jndi[#features.messaging.jms.jndi] -* xref:reference:actuator/jmx.adoc#actuator.jmx[#production-ready-jmx] -* xref:reference:data/sql.adoc#data.sql.jooq[#features.sql.jooq] -* xref:reference:data/sql.adoc#data.sql.jooq.codegen[#features.sql.jooq.codegen] -* xref:reference:data/sql.adoc#data.sql.jooq.customizing[#features.sql.jooq.customizing] -* xref:reference:data/sql.adoc#data.sql.jooq.dslcontext[#features.sql.jooq.dslcontext] -* xref:reference:data/sql.adoc#data.sql.jooq.sqldialect[#features.sql.jooq.sqldialect] -* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data[#features.sql.jpa-and-spring-data] -* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.open-entity-manager-in-view[#features.sql.jpa-and-spring-data.open-entity-manager-in-view] -* xref:reference:features/json.adoc#features.json[#boot-features-json] -* xref:reference:features/json.adoc#features.json.jackson.custom-serializers-and-deserializers[#web.servlet.spring-mvc.json] -* xref:reference:features/json.adoc#features.json.gson[#boot-features-json-gson] -* xref:reference:features/json.adoc#features.json.jackson[#boot-features-json-jackson] -* xref:reference:features/json.adoc#features.json.json-b[#boot-features-json-json-b] -* xref:reference:web/servlet.adoc#web.servlet.embedded-container.jsp-limitations[#features.developing-web-applications.embedded-container.jsp-limitations] -* xref:reference:io/jta.adoc#io.jta[#features.jta] -* xref:reference:io/jta.adoc#io.jta.jakartaee[#features.jta.javaee] -* xref:reference:io/jta.adoc#io.jta.mixing-xa-and-non-xa-connections[#features.jta.mixing-xa-and-non-xa-connections] -* xref:reference:io/jta.adoc#io.jta.supporting-embedded-transaction-manager[#features.jta.supporting-alternative-embedded-transaction-manager] -* xref:reference:messaging/kafka.adoc#messaging.kafka[#features.messaging.kafka] -* xref:reference:messaging/kafka.adoc#messaging.kafka.additional-properties[#features.messaging.kafka.additional-properties] -* xref:reference:messaging/kafka.adoc#messaging.kafka.receiving[#features.messaging.kafka.receiving] -* xref:reference:messaging/kafka.adoc#messaging.kafka.sending[#features.messaging.kafka.sending] -* xref:reference:messaging/kafka.adoc#messaging.kafka.streams[#features.messaging.kafka.streams] -* xref:reference:features/kotlin.adoc#features.kotlin[#boot-features-kotlin] -* xref:reference:features/kotlin.adoc#features.kotlin.api[#boot-features-kotlin-api] -* xref:reference:features/kotlin.adoc#features.kotlin.api.extensions[#boot-features-kotlin-api-extensions] -* xref:reference:features/kotlin.adoc#features.kotlin.api.run-application[#boot-features-kotlin-api-runapplication] -* xref:reference:features/kotlin.adoc#features.kotlin.configuration-properties[#boot-features-kotlin-configuration-properties] -* xref:reference:features/kotlin.adoc#features.kotlin.dependency-management[#boot-features-kotlin-dependency-management] -* xref:reference:features/kotlin.adoc#features.kotlin.null-safety[#boot-features-kotlin-null-safety] -* xref:reference:features/kotlin.adoc#features.kotlin.requirements[#boot-features-kotlin-requirements] -* xref:reference:features/kotlin.adoc#features.kotlin.resources[#boot-features-kotlin-resources] -* xref:reference:features/kotlin.adoc#features.kotlin.resources.examples[#boot-features-kotlin-resources-examples] -* xref:reference:features/kotlin.adoc#features.kotlin.resources.further-reading[#boot-features-kotlin-resources-further-reading] -* xref:reference:features/kotlin.adoc#features.kotlin.testing[#boot-features-kotlin-testing] -* xref:reference:features/spring-application.adoc#features.spring-application.lazy-initialization[#boot-features-lazy-initialization] -* xref:reference:data/nosql.adoc#data.nosql.ldap[#features.nosql.ldap] -* xref:reference:data/nosql.adoc#data.nosql.ldap.connecting[#features.nosql.ldap.connecting] -* xref:reference:data/nosql.adoc#data.nosql.ldap.embedded[#features.nosql.ldap.embedded] -* xref:reference:data/nosql.adoc#data.nosql.ldap.repositories[#features.nosql.ldap.repositories] -* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.locating-auto-configuration-candidates[#boot-features-locating-auto-configuration-candidates] -* xref:reference:features/logging.adoc#features.logging.shutdown-hook[#boot-features-log-shutdown-hook] -* xref:reference:features/logging.adoc#features.logging.logback-extensions.environment-properties[#boot-features-logback-environment-properties] -* xref:reference:features/logging.adoc#features.logging.logback-extensions[#boot-features-logback-extensions] -* xref:reference:features/logging.adoc#features.logging.logback-extensions.profile-specific[#boot-features-logback-extensions-profile-specific] -* xref:reference:features/logging.adoc#features.logging[#boot-features-logging] -* xref:reference:features/logging.adoc#features.logging.console-output.color-coded[#boot-features-logging-color-coded-output] -* xref:reference:features/logging.adoc#features.logging.console-output[#boot-features-logging-console-output] -* xref:reference:features/logging.adoc#features.logging.file-output[#boot-features-logging-file-output] -* xref:reference:features/logging.adoc#features.logging.file-rotation[#boot-features-logging-file-rotation] -* xref:reference:features/logging.adoc#features.logging.log-format[#boot-features-logging-format] -* xref:reference:messaging/index.adoc#messaging[#features.messaging] -* xref:reference:data/nosql.adoc#data.nosql.mongodb.template[#features.nosql.mongodb.template] -* xref:reference:data/nosql.adoc#data.nosql.mongodb[#features.nosql.mongodb] -* xref:reference:data/nosql.adoc#data.nosql.neo4j[#features.nosql.neo4j] -* xref:reference:data/nosql.adoc#data.nosql[#features.nosql] -* xref:reference:testing/test-utilities.adoc#testing.utilities.output-capture[#boot-features-output-capture-test-utility] -* xref:reference:features/profiles.adoc#features.profiles.profile-specific-configuration-files[#boot-features-profile-specific-configuration] -* xref:reference:features/profiles.adoc#features.profiles[#boot-features-profiles] -* xref:reference:features/profiles.adoc#features.profiles.groups[#boot-features-profiles-groups] -* xref:reference:web/servlet.adoc#web.servlet.embedded-container.customizing.programmatic[#features.developing-web-applications.embedded-container.customizing.programmatic] -* xref:reference:features/profiles.adoc#features.profiles.programmatically-setting-profiles[#boot-features-programmatically-setting-profiles] -* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.property-conditions[#boot-features-property-conditions] -* xref:reference:io/quartz.adoc#io.quartz[#features.quartz] -* xref:reference:data/sql.adoc#data.sql.r2dbc[#features.sql.r2dbc] -* xref:reference:data/sql.adoc#data.sql.r2dbc.embedded[#features.sql.r2dbc.embedded] -* xref:reference:data/sql.adoc#data.sql.r2dbc.using-database-client[#features.sql.r2dbc.using-database-client] -* xref:reference:messaging/amqp.adoc#messaging.amqp.rabbitmq[#features.messaging.amqp.rabbit] -* xref:reference:web/reactive.adoc#web.reactive.reactive-server[#features.developing-web-applications.reactive-server] -* xref:reference:web/reactive.adoc#web.reactive.reactive-server-resources-configuration[#features.developing-web-applications.reactive-server-resources-configuration] -* xref:reference:data/nosql.adoc#data.nosql.redis[#features.nosql.redis] -* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.resource-conditions[#boot-features-resource-conditions] -* xref:reference:testing/test-utilities.adoc#testing.utilities.test-rest-template[#boot-features-rest-templates-test-utility] -* xref:reference:io/rest-client.adoc#io.rest-client.resttemplate[#features.resttemplate] -* xref:reference:io/rest-client.adoc#io.rest-client.resttemplate.customization[#features.resttemplate.customization] -* xref:reference:messaging/rsocket.adoc#messaging.rsocket[#features.rsocket] -* xref:reference:messaging/rsocket.adoc#messaging.rsocket.messaging[#features.rsocket.messaging] -* xref:reference:messaging/rsocket.adoc#messaging.rsocket.requester[#features.rsocket.requester] -* xref:reference:messaging/rsocket.adoc#messaging.rsocket.server-auto-configuration[#features.rsocket.server-auto-configuration] -* xref:reference:messaging/rsocket.adoc#messaging.rsocket.strategies-auto-configuration[#features.rsocket.strategies-auto-configuration] -* xref:reference:web/spring-security.adoc#web.security[#features.security] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.security[#production-ready-endpoints-security] -* xref:reference:web/spring-security.adoc#web.security.oauth2.authorization-server[#features.security.authorization-server] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.security.csrf[#features.security.actuator.csrf] -* xref:reference:web/spring-security.adoc#web.security.spring-mvc[#features.security.spring-mvc] -* xref:reference:web/spring-security.adoc#web.security.oauth2[#features.security.oauth2] -* xref:reference:web/spring-security.adoc#web.security.oauth2.client[#features.security.oauth2.client] -* xref:reference:web/spring-security.adoc#web.security.oauth2.client.common-providers[#features.security.oauth2.client.common-providers] -* xref:reference:web/spring-security.adoc#web.security.oauth2.server[#features.security.oauth2.server] -* xref:reference:web/spring-security.adoc#web.security.saml2[#features.security.saml2] -* xref:reference:web/spring-security.adoc#web.security.saml2.relying-party[#features.security.saml2.relying-party] -* xref:reference:web/spring-security.adoc#web.security.spring-webflux[#features.security.spring-webflux] -* xref:reference:web/spring-session.adoc#web.spring-session[#features.spring-session] -* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.spel-conditions[#boot-features-spel-conditions] -* xref:reference:features/spring-application.adoc#features.spring-application[#boot-features-spring-application] -* xref:reference:data/nosql.adoc#data.nosql.cassandra.repositories[#features.nosql.cassandra.repositories] -* xref:reference:data/nosql.adoc#data.nosql.couchbase.repositories[#features.nosql.couchbase.repositories] -* xref:reference:data/nosql.adoc#data.nosql.elasticsearch.repositories[#features.nosql.elasticsearch.repositories] -* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.repositories[#features.sql.jpa-and-spring-data.repositories] -* xref:reference:data/nosql.adoc#data.nosql.mongodb.repositories[#features.nosql.mongodb.repositories] -* xref:reference:data/nosql.adoc#data.nosql.neo4j.repositories[#features.nosql.neo4j.repositories] -* xref:reference:data/sql.adoc#data.sql.r2dbc.repositories[#features.sql.r2dbc.repositories] -* xref:reference:web/spring-hateoas.adoc#web.spring-hateoas[#features.spring-hateoas] -* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.message-codes[#features.developing-web-applications.spring-mvc.message-codes] -* xref:reference:web/servlet.adoc#web.servlet.spring-mvc[#features.developing-web-applications.spring-mvc] -* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.auto-configuration[#features.developing-web-applications.spring-mvc.auto-configuration] -* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.message-converters[#features.developing-web-applications.spring-mvc.message-converters] -* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.content-negotiation[#features.developing-web-applications.spring-mvc.content-negotiation] -* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.static-content[#features.developing-web-applications.spring-mvc.static-content] -* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.template-engines[#features.developing-web-applications.spring-mvc.template-engines] -* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.binding-initializer[#features.developing-web-applications.spring-mvc.binding-initializer] -* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.welcome-page[#features.developing-web-applications.spring-mvc.welcome-page] -* xref:reference:data/sql.adoc#data.sql[#features.sql] -* xref:reference:data/sql.adoc#data.sql.h2-web-console[#features.sql.h2-web-console] -* xref:reference:data/sql.adoc#data.sql.h2-web-console.custom-path[#features.sql.h2-web-console.custom-path] -* xref:reference:features/spring-application.adoc#features.spring-application.startup-failure[#boot-features-startup-failure] -* xref:reference:features/task-execution-and-scheduling.adoc#features.task-execution-and-scheduling[#boot-features-task-execution-scheduling] -* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.testing[#boot-features-test-autoconfig] -* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.testing.overriding-classpath[#boot-features-test-autoconfig-overriding-classpath] -* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.testing.simulating-a-web-context[#boot-features-test-autoconfig-simulating-web-context] -* xref:reference:testing/test-utilities.adoc#testing.utilities.test-property-values[#boot-features-test-property-values] -* xref:reference:testing/test-scope-dependencies.adoc#testing.test-scope-dependencies[#boot-features-test-scope-dependencies] -* xref:reference:testing/test-utilities.adoc#testing.utilities[#boot-features-test-utilities] -* xref:reference:testing/index.adoc#testing[#boot-features-testing] -* xref:reference:testing/spring-applications.adoc#testing.spring-applications[#boot-features-testing-spring-applications] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.using-application-arguments[#boot-features-testing-spring-boot-application-arguments] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications[#boot-features-testing-spring-boot-applications] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.customizing-web-test-client[#boot-features-testing-spring-boot-applications-customizing-web-test-client] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.detecting-configuration[#boot-features-testing-spring-boot-applications-detecting-config] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.detecting-web-app-type[#boot-features-testing-spring-boot-applications-detecting-web-app-type] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.excluding-configuration[#boot-features-testing-spring-boot-applications-excluding-config] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.jmx[#boot-features-testing-spring-boot-applications-jmx] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.metrics[#boot-features-testing-spring-boot-applications-metrics] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.mocking-beans[#boot-features-testing-spring-boot-applications-mocking-beans] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.additional-autoconfiguration-and-slicing[#boot-features-testing-spring-boot-applications-testing-auto-configured-additional-auto-config] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-cassandra[#boot-features-testing-spring-boot-applications-testing-autoconfigured-cassandra-test] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-jdbc[#boot-features-testing-spring-boot-applications-testing-autoconfigured-data-jdbc-test] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-jdbc[#boot-features-testing-spring-boot-applications-testing-autoconfigured-jdbc-test] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-jooq[#boot-features-testing-spring-boot-applications-testing-autoconfigured-jooq-test] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-jpa[#boot-features-testing-spring-boot-applications-testing-autoconfigured-jpa-test] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.json-tests[#boot-features-testing-spring-boot-applications-testing-autoconfigured-json-tests] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-ldap[#boot-features-testing-spring-boot-applications-testing-autoconfigured-ldap-test] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-mongodb[#boot-features-testing-spring-boot-applications-testing-autoconfigured-mongo-test] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.spring-mvc-tests[#boot-features-testing-spring-boot-applications-testing-autoconfigured-mvc-tests] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-neo4j[#boot-features-testing-spring-boot-applications-testing-autoconfigured-neo4j-test] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-redis[#boot-features-testing-spring-boot-applications-testing-autoconfigured-redis-test] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-rest-client[#boot-features-testing-spring-boot-applications-testing-autoconfigured-rest-client] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-restdocs[#boot-features-testing-spring-boot-applications-testing-autoconfigured-rest-docs] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-restdocs.with-mock-mvc[#boot-features-testing-spring-boot-applications-testing-autoconfigured-rest-docs-mock-mvc] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-restdocs.with-rest-assured[#boot-features-testing-spring-boot-applications-testing-autoconfigured-rest-docs-rest-assured] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-restdocs.with-web-test-client[#boot-features-testing-spring-boot-applications-testing-autoconfigured-rest-docs-web-test-client] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-tests[#boot-features-testing-spring-boot-applications-testing-autoconfigured-tests] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.spring-webflux-tests[#boot-features-testing-spring-boot-applications-testing-autoconfigured-webflux-tests] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-webservices[#boot-features-testing-spring-boot-applications-testing-autoconfigured-webservices] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.user-configuration-and-slicing[#boot-features-testing-spring-boot-applications-testing-user-configuration] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.with-mock-environment[#boot-features-testing-spring-boot-applications-testing-with-mock-environment] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.with-running-server[#boot-features-testing-spring-boot-applications-testing-with-running-server] -* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.spock[#boot-features-testing-spring-boot-applications-with-spock] -* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.understanding-auto-configured-beans[#boot-features-understanding-auto-configured-beans] -* xref:reference:messaging/amqp.adoc#messaging.amqp.receiving[#features.messaging.amqp.receiving] -* xref:reference:messaging/amqp.adoc#messaging.amqp.sending[#features.messaging.amqp.sending] -* xref:reference:data/sql.adoc#data.sql.jdbc-template[#features.sql.jdbc-template] -* xref:reference:messaging/jms.adoc#messaging.jms.receiving[#features.messaging.jms.receiving] -* xref:reference:messaging/jms.adoc#messaging.jms.sending[#features.messaging.jms.sending] -* xref:reference:io/validation.adoc#io.validation[#features.validation] -* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.web-application-conditions[#boot-features-web-application-conditions] -* xref:reference:features/spring-application.adoc#features.spring-application.web-environment[#boot-features-web-environment] -* xref:reference:io/rest-client.adoc#io.rest-client.webclient[#features.webclient] -* xref:reference:io/rest-client.adoc#io.rest-client.webclient.customization[#features.webclient.customization] -* xref:reference:io/rest-client.adoc#io.rest-client.webclient.runtime[#features.webclient.runtime] -* xref:reference:web/reactive.adoc#web.reactive.webflux[#features.developing-web-applications.spring-webflux] -* xref:reference:web/reactive.adoc#web.reactive.webflux.auto-configuration[#features.developing-web-applications.spring-webflux.auto-configuration] -* xref:reference:web/reactive.adoc#web.reactive.webflux.error-handling[#features.developing-web-applications.spring-webflux.error-handling] -* xref:reference:web/reactive.adoc#web.reactive.webflux.error-handling.error-pages[#features.developing-web-applications.spring-webflux.error-pages] -* xref:reference:web/reactive.adoc#web.reactive.webflux.httpcodecs[#features.developing-web-applications.spring-webflux.httpcodecs] -* xref:reference:web/reactive.adoc#web.reactive.webflux.static-content[#features.developing-web-applications.spring-webflux.static-context] -* xref:reference:web/reactive.adoc#web.reactive.webflux.template-engines[#features.developing-web-applications.spring-webflux.template-engines] -* xref:reference:web/reactive.adoc#web.reactive.webflux.web-filters[#features.developing-web-applications.spring-webflux.web-filters] -* xref:reference:web/reactive.adoc#web.reactive.webflux.welcome-page[#features.developing-web-applications.spring-webflux.welcome-page] -* xref:reference:io/webservices.adoc#io.webservices[#features.webservices] -* xref:reference:io/webservices.adoc#io.webservices.template[#features.webservices.template] -* xref:reference:messaging/websockets.adoc#messaging.websockets[#features.websockets] -* xref:reference:packaging/container-images/efficient-images.adoc#packaging.container-images.efficient-images.layering[#features.container-images.layering] -* xref:build-tool-plugin:index.adoc#build-tool-plugins[#build-tool-plugins] -* xref:build-tool-plugin:antlib.adoc#build-tool-plugins.antlib[#build-tool-plugins-antlib] -* xref:build-tool-plugin:other-build-systems.adoc#build-tool-plugins.other-build-systems.finding-main-class[#build-tool-plugins-find-a-main-class] -* xref:reference:using/build-systems.adoc#using.build-systems.gradle[#using-boot-gradle] -* xref:reference:using/build-systems.adoc#using.build-systems.maven[#using-boot-maven] -* xref:build-tool-plugin:other-build-systems.adoc#build-tool-plugins.other-build-systems.nested-libraries[#build-tool-plugins-nested-libraries] -* xref:build-tool-plugin:other-build-systems.adoc#build-tool-plugins.other-build-systems[#build-tool-plugins-other-build-systems] -* xref:build-tool-plugin:other-build-systems.adoc#build-tool-plugins.other-build-systems.example-repackage-implementation[#build-tool-plugins-repackage-implementation] -* xref:build-tool-plugin:other-build-systems.adoc#build-tool-plugins.other-build-systems.repackaging-archives[#build-tool-plugins-repackaging-archives] -* xref:cli:index.adoc#cli[#cli] -* xref:cli:using-the-cli.adoc#cli.using-the-cli.initialize-new-project[#cli-init] -* xref:cli:installation.adoc#cli.installation[#cli-installation] -* xref:cli:using-the-cli.adoc#cli.using-the-cli.embedded-shell[#cli-shell] -* xref:cli:using-the-cli.adoc#cli.using-the-cli[#cli-using-the-cli] -* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud[#cloud-deployment] -* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws[#cloud-deployment-aws] -* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws.beanstalk[#cloud-deployment-aws-beanstalk] -* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws.beanstalk.java-se-platform[#cloud-deployment-aws-java-se-platform] -* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws.summary[#cloud-deployment-aws-summary] -* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws.beanstalk.tomcat-platform[#cloud-deployment-aws-tomcat-platform] -* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.boxfuse[#cloud-deployment-boxfuse] -* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.cloud-foundry[#cloud-deployment-cloud-foundry] -* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.cloud-foundry.binding-to-services[#cloud-deployment-cloud-foundry-services] -* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.google[#cloud-deployment-gae] -* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.heroku[#cloud-deployment-heroku] -* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.kubernetes[#cloud-deployment-kubernetes] -* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.kubernetes.container-lifecycle[#cloud-deployment-kubernetes-container-lifecycle] -* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.openshift[#cloud-deployment-openshift] -* xref:specification:configuration-metadata/index.adoc#appendix.configuration-metadata[#configuration-metadata] -* xref:specification:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.adding-additional-metadata[#configuration-metadata.annotation-processor.adding-additional-metadata] -* xref:specification:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor[#configuration-metadata.annotation-processor] -* xref:specification:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.automatic-metadata-generation[#configuration-metadata.annotation-processor.automatic-metadata-generation] -* xref:specification:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.automatic-metadata-generation.nested-properties[#configuration-metadata.annotation-processor.automatic-metadata-generation.nested-properties] -* xref:specification:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.configuring[#configuration-metadata.annotation-processor.configuring] -* xref:specification:configuration-metadata/format.adoc#appendix.configuration-metadata.format[#configuration-metadata.format] -* xref:specification:configuration-metadata/format.adoc#appendix.configuration-metadata.format.group[#configuration-metadata.format.group] -* xref:specification:configuration-metadata/format.adoc#appendix.configuration-metadata.format.hints[#configuration-metadata.format.hints] -* xref:specification:configuration-metadata/format.adoc#appendix.configuration-metadata.format.property[#configuration-metadata.format.property] -* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints[#configuration-metadata.manual-hints] -* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers.any[#configuration-metadata.manual-hints.value-providers.any] -* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers.class-reference[#configuration-metadata.manual-hints.value-providers.class-reference] -* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers.handle-as[#configuration-metadata.manual-hints.value-providers.handle-as] -* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers.logger-name[#configuration-metadata.manual-hints.value-providers.logger-name] -* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers.spring-bean-reference[#configuration-metadata.manual-hints.value-providers.spring-bean-reference] -* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers.spring-profile-name[#configuration-metadata.manual-hints.value-providers.spring-profile-name] -* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-hint[#configuration-metadata.manual-hints.value-hint] -* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers[#configuration-metadata.manual-hints.value-providers] -* xref:specification:configuration-metadata/format.adoc#appendix.configuration-metadata.format.repeated-items[#configuration-metadata.format.repeated-items] -* xref:reference:using/devtools.adoc#using.devtools.globalsettings.configuring-file-system-watcher[#configuring-file-system-watcher] -* xref:reference:packaging/efficient.adoc#packaging.efficient.unpacking[#container-images.efficient-images.unpacking] -* xref:reference:data/nosql.adoc#data.nosql.elasticsearch.connecting-using-rest.reactiveclient[#data.nosql.elasticsearch.connecting-using-rest.webclient] -* xref:appendix:dependency-versions/index.adoc#appendix.dependency-versions[#dependency-versions] -* xref:appendix:dependency-versions/coordinates.adoc#appendix.dependency-versions.coordinates[#dependency-versions.coordinates] -* xref:appendix:dependency-versions/properties.adoc#appendix.dependency-versions.properties[#dependency-versions.properties] -* xref:how-to:deployment/index.adoc#howto.deployment[#deployment] -* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d[#deployment.installing.nix-services.init-d] -* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d.securing[#deployment.installing.nix-services.init-d.securing] -* xref:how-to:deployment/installing.adoc#howto.deployment.installing[#deployment.installing.supported-operating-systems] -* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d.script-customization[#deployment.installing.nix-services.script-customization] -* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d.script-customization.when-running[#deployment.installing.nix-services.script-customization.when-running] -* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d.script-customization.when-written[#deployment.installing.nix-services.script-customization.when-written] -* xref:how-to:deployment/installing.adoc#howto.deployment.installing.system-d[#deployment.installing.nix-services.system-d] -* xref:how-to:deployment/installing.adoc#howto.deployment.installing.windows-services[#deployment-windows] -* xref:how-to:deployment/installing.adoc#howto.deployment.installing.init-d.script-customization.when-running.conf-file[#deployment.installing.nix-services.script-customization.when-running.conf-file] -* xref:specification:executable-jar/index.adoc#appendix.executable-jar[#executable-jar] -* xref:specification:executable-jar/alternatives.adoc#appendix.executable-jar.alternatives[#executable-jar.alternatives] -* xref:specification:executable-jar/nested-jars.adoc#appendix.executable-jar.nested-jars.jar-structure[#executable-jar.nested-jars.jar-structure] -* xref:specification:executable-jar/jarfile-class.adoc#appendix.executable-jar.jarfile-class[#executable-jar.jarfile-class] -* xref:specification:executable-jar/jarfile-class.adoc#appendix.executable-jar.jarfile-class.compatibility[#executable-jar.jarfile-class.compatibility] -* xref:specification:executable-jar/launching.adoc#appendix.executable-jar.launching.manifest[#executable-jar.launching.manifest] -* xref:specification:executable-jar/launching.adoc#appendix.executable-jar.launching[#executable-jar.launching] -* xref:specification:executable-jar/nested-jars.adoc#appendix.executable-jar.nested-jars[#executable-jar.nested-jars] -* xref:specification:executable-jar/property-launcher.adoc#appendix.executable-jar.property-launcher[#executable-jar.property-launcher] -* xref:specification:executable-jar/restrictions.adoc#appendix.executable-jar.restrictions[#executable-jar.restrictions] -* xref:specification:executable-jar/nested-jars.adoc#appendix.executable-jar.nested-jars.war-structure[#executable-jar.nested-jars.war-structure] -* xref:specification:executable-jar/nested-jars.adoc#appendix.executable-jar.nested-jars.index-files[#executable-jar.nested-jars.index-files] -* xref:specification:executable-jar/nested-jars.adoc#appendix.executable-jar.nested-jars.classpath-index[#executable-jar.nested-jars.classpath-index] -* xref:specification:executable-jar/nested-jars.adoc#appendix.executable-jar.nested-jars.layer-index[#executable-jar.nested-jars.layer-index] -* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.favicon[#features.developing-web-applications.spring-mvc.favicon] -* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.envers-repositories[#features.sql.jpa-and-spring-data.envers-repositories] -* xref:reference:features/dev-services.adoc#features.dev-services.testcontainers.at-development-time[#features.testing.testcontainers.at-development-time] -* xref:reference:features/dev-services.adoc#features.dev-services.testcontainers.at-development-time.devtools[#features.testing.testcontainers.at-development-time.devtools] -* xref:reference:features/dev-services.adoc#features.dev-services.testcontainers.at-development-time.dynamic-properties[#features.testing.testcontainers.at-development-time.dynamic-properties] -* xref:reference:features/dev-services.adoc#features.dev-services.testcontainers.at-development-time.importing-container-declarations[#features.testing.testcontainers.at-development-time.importing-container-declarations] -* xref:index.adoc[#index] -* xref:ROOT:installing.adoc#getting-started.installing.cli.completion[#getting-started-cli-command-line-completion] -* xref:tutorial:first-application/index.adoc#getting-started.first-application[#getting-started-first-application] -* xref:tutorial:first-application/index.adoc#getting-started.first-application.code.mvc-annotations[#getting-started-first-application-annotations] -* xref:tutorial:first-application/index.adoc#getting-started.first-application.code.spring-boot-application[#getting-started.first-application.code.enable-auto-configuration] -* xref:tutorial:first-application/index.adoc#getting-started.first-application.code[#getting-started-first-application-code] -* xref:tutorial:first-application/index.adoc#getting-started.first-application.dependencies[#getting-started-first-application-dependencies] -* xref:tutorial:first-application/index.adoc#getting-started.first-application.executable-jar[#getting-started-first-application-executable-jar] -* xref:tutorial:first-application/index.adoc#getting-started.first-application.code.main-method[#getting-started-first-application-main-method] -* xref:tutorial:first-application/index.adoc#getting-started.first-application.pom[#getting-started-first-application-pom] -* xref:tutorial:first-application/index.adoc#getting-started.first-application.run[#getting-started-first-application-run] -* xref:ROOT:installing.adoc#getting-started.installing.java.gradle[#getting-started-gradle-installation] -* xref:ROOT:installing.adoc#getting-started.installing.cli.homebrew[#getting-started-homebrew-cli-installation] -* xref:ROOT:installing.adoc#getting-started.installing.java[#getting-started-installation-instructions-for-java] -* xref:ROOT:installing.adoc#getting-started.installing[#getting-started-installing-spring-boot] -* xref:ROOT:installing.adoc#getting-started.installing.cli[#getting-started-installing-the-cli] -* xref:ROOT:installing.adoc#getting-started.installing.cli.macports[#getting-started-macports-cli-installation] -* xref:ROOT:installing.adoc#getting-started.installing.cli.manual-installation[#getting-started-manual-cli-installation] -* xref:ROOT:installing.adoc#getting-started.installing.java.maven[#getting-started-maven-installation] -* xref:ROOT:installing.adoc#getting-started.installing.cli.scoop[#getting-started-scoop-cli-installation] -* xref:ROOT:installing.adoc#getting-started.installing.cli.sdkman[#getting-started-sdkman-cli-installation] -* xref:ROOT:system-requirements.adoc#getting-started.system-requirements[#getting-started-system-requirements] -* xref:ROOT:system-requirements.adoc#getting-started.system-requirements.servlet-containers[#getting-started-system-requirements-servlet-containers] -* xref:ROOT:upgrading.adoc#upgrading[#getting-started.installing.upgrading] -* xref:how-to:webserver.adoc#howto.webserver.enable-response-compression[#how-to-enable-http-response-compression] -* xref:how-to:index.adoc#howto[#howto] -* xref:how-to:actuator.adoc#howto.actuator[#howto-actuator] -* xref:how-to:webserver.adoc#howto.webserver.add-servlet-filter-listener[#howto-add-a-servlet-filter-or-listener] -* xref:how-to:webserver.adoc#howto.webserver.add-servlet-filter-listener.spring-bean[#howto-add-a-servlet-filter-or-listener-as-spring-bean] -* xref:how-to:webserver.adoc#howto.webserver.add-servlet-filter-listener.using-scanning[#howto-add-a-servlet-filter-or-listener-using-scanning] -* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.expand-properties[#howto-automatic-expansion] -* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.expand-properties.gradle[#howto-automatic-expansion-gradle] -* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.expand-properties.maven[#howto-automatic-expansion-maven] -* xref:how-to:batch.adoc#howto.batch[#howto-batch-applications] -* xref:how-to:build.adoc#howto.build[#howto-build] -* xref:how-to:application.adoc#howto.application.context-hierarchy[#howto-build-an-application-context-hierarchy] -* xref:how-to:build.adoc#howto.build.build-an-executable-archive-with-ant-without-using-spring-boot-antlib[#howto-build-an-executable-archive-with-ant] -* xref:how-to:build.adoc#howto.build.generate-info[#howto-build-info] -* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.change-configuration-depending-on-the-environment[#howto-change-configuration-depending-on-the-environment] -* xref:how-to:webserver.adoc#howto.webserver.change-port[#howto-change-the-http-port] -* xref:how-to:actuator.adoc#howto.actuator.change-http-port-or-address[#howto-change-the-http-port-or-address-of-the-actuator-endpoints] -* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.external-properties-location[#howto-change-the-location-of-external-properties] -* xref:how-to:security.adoc#howto.security.change-user-details-service-and-add-user-accounts[#howto-change-the-user-details-service-and-add-user-accounts] -* xref:how-to:data-access.adoc#howto.data-access.configure-a-component-that-is-used-by-jpa[#howto-configure-a-component-that-is-used-by-JPA] -* xref:how-to:data-access.adoc#howto.data-access.configure-custom-datasource[#howto-configure-a-datasource] -* xref:how-to:webserver.adoc#howto.webserver.configure-access-logs[#howto-configure-accesslogs] -* xref:how-to:data-access.adoc#howto.data-access.configure-hibernate-naming-strategy[#howto-configure-hibernate-naming-strategy] -* xref:how-to:data-access.adoc#howto.data-access.configure-hibernate-second-level-caching[#howto-configure-hibernate-second-level-caching] -* xref:how-to:webserver.adoc#howto.webserver.configure-http2[#howto-configure-http2] -* xref:how-to:webserver.adoc#howto.webserver.configure-http2.jetty[#howto-configure-http2-jetty] -* xref:how-to:webserver.adoc#howto.webserver.configure-http2.netty[#howto-configure-http2-netty] -* xref:how-to:webserver.adoc#howto.webserver.configure-http2.tomcat[#howto-configure-http2-tomcat] -* xref:how-to:webserver.adoc#howto.webserver.configure-http2.undertow[#howto-configure-http2-undertow] -* xref:how-to:data-access.adoc#howto.data-access.configure-jooq-with-multiple-datasources[#howto-configure-jOOQ-with-multiple-datasources] -* xref:how-to:data-access.adoc#howto.data-access.jpa-properties[#howto-configure-jpa-properties] -* xref:how-to:logging.adoc#howto.logging.log4j[#howto-configure-log4j-for-logging] -* xref:how-to:logging.adoc#howto.logging.log4j.yaml-or-json-config[#howto-configure-log4j-for-logging-yaml-or-json-config] -* xref:how-to:logging.adoc#howto.logging.logback[#howto-configure-logback-for-logging] -* xref:how-to:logging.adoc#howto.logging.logback.file-only-output[#howto-configure-logback-for-logging-fileonly] -* xref:how-to:webserver.adoc#howto.webserver.configure-ssl[#howto-configure-ssl] -* xref:how-to:webserver.adoc#howto.webserver.configure[#howto-configure-webserver] -* xref:how-to:deployment/traditional-deployment.adoc#howto.traditional-deployment.convert-existing-application[#howto-convert-an-existing-application-to-spring-boot] -* xref:how-to:deployment/traditional-deployment.adoc#howto.traditional-deployment.war[#howto-create-a-deployable-war-file] -* xref:how-to:application.adoc#howto.application.non-web-application[#howto-create-a-non-web-application] -* xref:how-to:build.adoc#howto.build.create-a-nonexecutable-jar[#howto-create-a-nonexecutable-jar] -* xref:how-to:build.adoc#howto.build.use-a-spring-boot-application-as-dependency[#howto-create-an-additional-executable-jar] -* xref:how-to:build.adoc#howto.build.create-an-executable-jar-with-maven[#howto-create-an-executable-jar-with-maven] -* xref:how-to:webserver.adoc#howto.webserver.create-websocket-endpoints-using-serverendpoint[#howto-create-websocket-endpoints-using-serverendpoint] -* xref:how-to:build.adoc#howto.build.customize-dependency-versions[#howto-customize-dependency-versions] -* xref:how-to:application.adoc#howto.application.customize-the-environment-or-application-context[#howto-customize-the-environment-or-application-context] -* xref:how-to:spring-mvc.adoc#howto.spring-mvc.customize-jackson-objectmapper[#howto-customize-the-jackson-objectmapper] -* xref:how-to:spring-mvc.adoc#howto.spring-mvc.customize-responsebody-rendering[#howto-customize-the-responsebody-rendering] -* xref:how-to:spring-mvc.adoc#howto.spring-mvc.customize-whitelabel-error-page[#howto-customize-the-whitelabel-error-page] -* xref:how-to:webserver.adoc#howto.webserver.use-behind-a-proxy-server.tomcat[#howto-customize-tomcat-behind-a-proxy-server] -* xref:how-to:spring-mvc.adoc#howto.spring-mvc.customize-view-resolvers[#howto-customize-view-resolvers] -* xref:how-to:data-access.adoc#howto.data-access[#howto-data-access] -* xref:how-to:data-initialization.adoc#howto.data-initialization[#howto-database-initialization] -* xref:how-to:webserver.adoc#howto.webserver.add-servlet-filter-listener.spring-bean.disable[#howto-disable-registration-of-a-servlet-or-filter] -* xref:how-to:webserver.adoc#howto.webserver.disable[#howto-disable-web-server] -* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.discover-build-in-options-for-external-properties[#howto-discover-build-in-options-for-external-properties] -* xref:how-to:webserver.adoc#howto.webserver.discover-port[#howto-discover-the-http-port-at-runtime] -* xref:how-to:webserver.adoc#howto.webserver[#howto-embedded-web-servers] -* xref:how-to:security.adoc#howto.security.enable-https[#howto-enable-https] -* xref:how-to:webserver.adoc#howto.webserver.enable-multiple-connectors-in-tomcat[#howto-enable-multiple-connectors-in-tomcat] -* xref:how-to:webserver.adoc#howto.webserver.enable-multiple-listeners-in-undertow[#howto-enable-multiple-listeners-in-undertow] -* xref:how-to:webserver.adoc#howto.webserver.enable-tomcat-mbean-registry[#howto-enable-tomcat-mbean-registry] -* xref:how-to:data-initialization.adoc#howto.data-initialization.migration-tool.flyway[#howto-execute-flyway-database-migrations-on-startup] -* xref:how-to:data-initialization.adoc#howto.data-initialization.migration-tool.liquibase[#howto-execute-liquibase-database-migrations-on-startup] -* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.externalize-configuration[#howto-externalize-configuration] -* xref:how-to:build.adoc#howto.build.extract-specific-libraries-when-an-executable-jar-runs[#howto-extract-specific-libraries-when-an-executable-jar-runs] -* xref:how-to:application.adoc#howto.application.failure-analyzer[#howto-failure-analyzer] -* xref:how-to:build.adoc#howto.build.generate-git-info[#howto-git-info] -* xref:how-to:hotswapping.adoc#howto.hotswapping[#howto-hotswapping] -* xref:how-to:http-clients.adoc#howto.http-clients[#howto-http-clients] -* xref:how-to:http-clients.adoc#howto.http-clients.rest-template-proxy-configuration[#howto-http-clients-proxy-configuration] -* xref:how-to:data-initialization.adoc#howto.data-initialization.dependencies[#howto-initialize-a-database-configuring-dependencies] -* xref:how-to:data-initialization.adoc#howto.data-initialization.dependencies.depends-on-initialization-detection[#howto-initialize-a-database-configuring-dependencies-depends-on-initialization-detection] -* xref:how-to:data-initialization.adoc#howto.data-initialization.dependencies.initializer-detection[#howto-initialize-a-database-configuring-dependencies-initializer-detection] -* xref:how-to:data-initialization.adoc#howto.data-initialization.using-basic-sql-scripts[#howto-initialize-a-database-using-basic-scripts] -* xref:how-to:data-initialization.adoc#howto.data-initialization.using-hibernate[#howto.data-initialization.using-jpa] -* xref:how-to:data-initialization.adoc#howto.data-initialization.batch[#howto-initialize-a-spring-batch-database] -* xref:how-to:jersey.adoc#howto.jersey[#howto-jersey] -* xref:how-to:jersey.adoc#howto.jersey.alongside-another-web-framework[#howto-jersey-alongside-another-web-framework] -* xref:how-to:jersey.adoc#howto.jersey.spring-security[#howto-jersey-spring-security] -* xref:how-to:messaging.adoc#howto.messaging.disable-transacted-jms-session[#howto-jms-disable-transaction] -* xref:how-to:logging.adoc#howto.logging[#howto-logging] -* xref:how-to:actuator.adoc#howto.actuator.map-health-indicators-to-metrics[#howto-map-health-indicators-to-metrics] -* xref:how-to:messaging.adoc#howto.messaging[#howto-messaging] -* xref:how-to:spring-mvc.adoc#howto.spring-mvc.multipart-file-uploads[#howto-multipart-file-upload-configuration] -* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration[#howto-properties-and-configuration] -* xref:how-to:hotswapping.adoc#howto.hotswapping.fast-application-restarts[#howto-reload-fast-restart] -* xref:how-to:hotswapping.adoc#howto.hotswapping.reload-templates.freemarker[#howto-reload-freemarker-content] -* xref:how-to:hotswapping.adoc#howto.hotswapping.reload-templates.groovy[#howto-reload-groovy-template-content] -* xref:how-to:hotswapping.adoc#howto.hotswapping.reload-java-classes-without-restarting[#howto-reload-java-classes-without-restarting] -* xref:how-to:hotswapping.adoc#howto.hotswapping.reload-static-content[#howto-reload-static-content] -* xref:how-to:hotswapping.adoc#howto.hotswapping.reload-templates.thymeleaf[#howto-reload-thymeleaf-content] -* xref:how-to:hotswapping.adoc#howto.hotswapping.reload-templates[#howto-reload-thymeleaf-template-content] -* xref:how-to:build.adoc#howto.build.remote-debug-maven[#howto-remote-debug-maven-run] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.sanitization[#howto.actuator.sanitize-sensitive-values] -* xref:how-to:security.adoc#howto.security[#howto-security] -* xref:how-to:data-access.adoc#howto.data-access.separate-entity-definitions-from-spring-configuration[#howto-separate-entity-definitions-from-spring-configuration] -* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.set-active-spring-profiles[#howto-set-active-spring-profiles] -* xref:how-to:batch.adoc#howto.batch.running-from-the-command-line[#howto-spring-batch-running-command-line] -* xref:how-to:batch.adoc#howto.batch.running-jobs-on-startup[#howto-spring-batch-running-jobs-on-startup] -* xref:how-to:batch.adoc#howto.batch.specifying-a-data-source[#howto-spring-batch-specifying-a-data-source] -* xref:how-to:batch.adoc#howto.batch.storing-job-repository[#howto-spring-batch-storing-job-repository] -* xref:how-to:application.adoc#howto.application[#howto-spring-boot-application] -* xref:how-to:spring-mvc.adoc#howto.spring-mvc[#howto-spring-mvc] -* xref:how-to:spring-mvc.adoc#howto.spring-mvc.switch-off-default-configuration[#howto-switch-off-default-mvc-configuration] -* xref:how-to:security.adoc#howto.security.switch-off-spring-boot-configuration[#howto-switch-off-spring-boot-security-configuration] -* xref:how-to:spring-mvc.adoc#howto.spring-mvc.switch-off-dispatcherservlet[#howto-switch-off-the-spring-mvc-dispatcherservlet] -* xref:reference:testing/testcontainers.adoc#testing.testcontainers[#howto.testing.testcontainers] -* xref:how-to:deployment/traditional-deployment.adoc#howto.traditional-deployment[#howto-traditional-deployment] -* xref:how-to:application.adoc#howto.application.troubleshoot-auto-configuration[#howto-troubleshoot-auto-configuration] -* xref:how-to:data-access.adoc#howto.data-access.configure-two-datasources[#howto-two-datasources] -* xref:how-to:data-initialization.adoc#howto.data-initialization.migration-tool[#howto-use-a-higher-level-database-migration-tool] -* xref:how-to:webserver.adoc#howto.webserver.use-another[#howto-use-another-web-server] -* xref:how-to:webserver.adoc#howto.webserver.use-behind-a-proxy-server[#howto-use-behind-a-proxy-server] -* xref:how-to:data-access.adoc#howto.data-access.use-custom-entity-manager[#howto-use-custom-entity-manager] -* xref:how-to:data-access.adoc#howto.data-access.customize-spring-data-web-support[#howto-use-customize-spring-datas-web-support] -* xref:how-to:data-access.adoc#howto.data-access.dependency-injection-in-hibernate-components[#howto-use-dependency-injection-hibernate-components] -* xref:how-to:data-access.adoc#howto.data-access.exposing-spring-data-repositories-as-rest[#howto-use-exposing-spring-data-repositories-rest-endpoint] -* xref:how-to:nosql.adoc#howto.nosql.jedis-instead-of-lettuce[#howto-use-jedis-instead-of-lettuce] -* xref:how-to:data-access.adoc#howto.data-access.use-multiple-entity-managers[#howto-use-two-entity-managers] -* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.short-command-line-arguments[#howto-use-short-command-line-arguments] -* xref:how-to:data-access.adoc#howto.data-access.use-spring-data-jpa-and-mongo-repositories[#howto-use-spring-data-jpa--and-mongo-repositories] -* xref:how-to:data-access.adoc#howto.data-access.spring-data-repositories[#howto-use-spring-data-repositories] -* xref:how-to:testing.adoc#howto.testing.with-spring-security[#howto.spring-mvc.testing.with-spring-security] -* xref:how-to:data-access.adoc#howto.data-access.use-traditional-persistence-xml[#howto-use-traditional-persistence-xml] -* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.yaml[#howto-use-yaml-for-external-properties] -* xref:how-to:webserver.adoc#howto.webserver.use-random-port[#howto-user-a-random-unassigned-http-port] -* xref:how-to:http-clients.adoc#howto.http-clients.webclient-reactor-netty-customization[#howto-webclient-reactor-netty-customization] -* xref:how-to:deployment/traditional-deployment.adoc#howto.traditional-deployment.weblogic[#howto-weblogic] -* xref:how-to:spring-mvc.adoc#howto.spring-mvc.write-json-rest-service[#howto-write-a-json-rest-service] -* xref:how-to:spring-mvc.adoc#howto.spring-mvc.write-xml-rest-service[#howto-write-an-xml-rest-service] -* xref:how-to:actuator.adoc#howto.actuator.customizing-sanitization[#howto.actuator.sanitize-sensitive-values.customizing-sanitization] -* xref:reference:testing/testcontainers.adoc#testing.testcontainers.dynamic-properties[#howto.testing.testcontainers.dynamic-properties] -* xref:reference:actuator/index.adoc#actuator[#production-ready] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.info[#production-ready-application-info] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.info.auto-configured-info-contributors[#production-ready-application-info-autoconfigure] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.info.build-information[#production-ready-application-info-build] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.info.writing-custom-info-contributors[#production-ready-application-info-custom] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.info.custom-application-information[#production-ready-application-info-env] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.info.git-commit-information[#production-ready-application-info-git] -* xref:reference:actuator/auditing.adoc#actuator.auditing[#production-ready-auditing] -* xref:reference:actuator/auditing.adoc#actuator.auditing.custom[#production-ready-auditing-custom] -* xref:reference:actuator/cloud-foundry.adoc#actuator.cloud-foundry[#production-ready-cloudfoundry] -* xref:reference:actuator/cloud-foundry.adoc#actuator.cloud-foundry.disable[#production-ready-cloudfoundry-disable] -* xref:reference:actuator/cloud-foundry.adoc#actuator.cloud-foundry.ssl[#production-ready-cloudfoundry-ssl] -* xref:reference:actuator/cloud-foundry.adoc#actuator.cloud-foundry.custom-context-path[#production-ready-custom-context-path] -* xref:reference:actuator/jmx.adoc#actuator.jmx.custom-mbean-names[#production-ready-custom-mbean-names] -* xref:reference:actuator/monitoring.adoc#actuator.monitoring.customizing-management-server-address[#production-ready-customizing-management-server-address] -* xref:reference:actuator/monitoring.adoc#actuator.monitoring.customizing-management-server-context-path[#production-ready-customizing-management-server-context-path] -* xref:reference:actuator/monitoring.adoc#actuator.monitoring.customizing-management-server-port[#production-ready-customizing-management-server-port] -* xref:reference:actuator/jmx.adoc#actuator.jmx.disable-jmx-endpoints[#production-ready-disable-jmx-endpoints] -* xref:reference:actuator/monitoring.adoc#actuator.monitoring.disabling-http-endpoints[#production-ready-disabling-http-endpoints] -* xref:reference:actuator/enabling.adoc#actuator.enabling[#production-ready-enabling] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints[#production-ready-endpoints] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.caching[#production-ready-endpoints-caching] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.cors[#production-ready-endpoints-cors] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom[#production-ready-endpoints-custom] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.input[#production-ready-endpoints-custom-input] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.input.conversion[#production-ready-endpoints-custom-input-conversion] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web[#production-ready-endpoints-custom-web] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.request-predicates[#production-ready-endpoints-custom-web-predicate] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.consumes-predicates[#production-ready-endpoints-custom-web-predicate-consumes] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.method-predicates[#production-ready-endpoints-custom-web-predicate-http-method] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.path-predicates[#production-ready-endpoints-custom-web-predicate-path] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.produces-predicates[#production-ready-endpoints-custom-web-predicate-produces] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.range-requests[#production-ready-endpoints-custom-web-range-requests] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.response-status[#production-ready-endpoints-custom-web-response-status] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.security[#production-ready-endpoints-custom-web-security] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.enabling[#production-ready-endpoints-enabling-endpoints] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.exposing[#production-ready-endpoints-exposing-endpoints] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.hypermedia[#production-ready-endpoints-hypermedia] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.health[#production-ready-health] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.health.datasource[#production-ready-health-datasource] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.health.groups[#production-ready-health-groups] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.health.auto-configured-health-indicators[#production-ready-health-indicators] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.health.writing-custom-health-indicators[#production-ready-health-indicators-writing] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.kubernetes-probes[#production-ready-kubernetes-probes] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.kubernetes-probes.external-state[#production-ready-kubernetes-probes-external-state] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.kubernetes-probes.lifecycle[#production-ready-kubernetes-probes-lifecycle] -* xref:reference:actuator/loggers.adoc#actuator.loggers.configure[#production-ready-logger-configuration] -* xref:reference:actuator/loggers.adoc#actuator.loggers[#production-ready-loggers] -* xref:reference:actuator/monitoring.adoc#actuator.monitoring.management-specific-ssl[#production-ready-management-specific-ssl] -* xref:reference:actuator/metrics.adoc#actuator.metrics[#production-ready-metrics] -* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.cache[#production-ready-metrics-cache] -* xref:reference:actuator/metrics.adoc#actuator.metrics.customizing.common-tags[#production-ready-metrics-common-tags] -* xref:reference:actuator/metrics.adoc#actuator.metrics.registering-custom[#production-ready-metrics-custom] -* xref:reference:actuator/metrics.adoc#actuator.metrics.customizing[#production-ready-metrics-customizing] -* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.spring-data-repository[#production-ready-metrics-data-repository] -* xref:reference:actuator/metrics.adoc#actuator.metrics.endpoint[#production-ready-metrics-endpoint] -* xref:reference:actuator/metrics.adoc#actuator.metrics.export[#production-ready-metrics-export] -* xref:reference:actuator/metrics.adoc#actuator.metrics.export.appoptics[#production-ready-metrics-export-appoptics] -* xref:reference:actuator/metrics.adoc#actuator.metrics.export.atlas[#production-ready-metrics-export-atlas] -* xref:reference:actuator/metrics.adoc#actuator.metrics.export.datadog[#production-ready-metrics-export-datadog] -* xref:reference:actuator/metrics.adoc#actuator.metrics.export.dynatrace[#production-ready-metrics-export-dynatrace] -* xref:reference:actuator/metrics.adoc#actuator.metrics.export.elastic[#production-ready-metrics-export-elastic] -* xref:reference:actuator/metrics.adoc#actuator.metrics.export.ganglia[#production-ready-metrics-export-ganglia] -* xref:reference:actuator/metrics.adoc#actuator.metrics.export.graphite[#production-ready-metrics-export-graphite] -* xref:reference:actuator/metrics.adoc#actuator.metrics.export.humio[#production-ready-metrics-export-humio] -* xref:reference:actuator/metrics.adoc#actuator.metrics.export.influx[#production-ready-metrics-export-influx] -* xref:reference:actuator/metrics.adoc#actuator.metrics.export.jmx[#production-ready-metrics-export-jmx] -* xref:reference:actuator/metrics.adoc#actuator.metrics.export.kairos[#production-ready-metrics-export-kairos] -* xref:reference:actuator/metrics.adoc#actuator.metrics.export.newrelic[#production-ready-metrics-export-newrelic] -* xref:reference:actuator/metrics.adoc#actuator.metrics.export.prometheus[#production-ready-metrics-export-prometheus] -* xref:reference:actuator/metrics.adoc#actuator.metrics.export.signalfx[#production-ready-metrics-export-signalfx] -* xref:reference:actuator/metrics.adoc#actuator.metrics.export.simple[#production-ready-metrics-export-simple] -* xref:reference:actuator/metrics.adoc#actuator.metrics.export.stackdriver[#production-ready-metrics-export-stackdriver] -* xref:reference:actuator/metrics.adoc#actuator.metrics.export.statsd[#production-ready-metrics-export-statsd] -* xref:reference:actuator/metrics.adoc#actuator.metrics.export.wavefront[#production-ready-metrics-export-wavefront] -* xref:reference:actuator/metrics.adoc#actuator.metrics.getting-started[#production-ready-metrics-getting-started] -* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.hibernate[#production-ready-metrics-hibernate] -* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.http-clients[#production-ready-metrics-http-clients] -* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.spring-integration[#production-ready-metrics-integration] -* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.jdbc[#production-ready-metrics-jdbc] -* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.jersey[#production-ready-metrics-jersey-server] -* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.jvm[#production-ready-metrics-jvm] -* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.kafka[#production-ready-metrics-kafka] -* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.logger[#production-ready-metrics-logger] -* xref:reference:actuator/metrics.adoc#actuator.metrics.supported[#production-ready-metrics-meter] -* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.mongodb[#production-ready-metrics-mongodb] -* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.mongodb.command[#production-ready-metrics-mongodb-command] -* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.mongodb.connection-pool[#production-ready-metrics-mongodb-connectionpool] -* xref:reference:actuator/metrics.adoc#actuator.metrics.customizing.per-meter-properties[#production-ready-metrics-per-meter-properties] -* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.rabbitmq[#production-ready-metrics-rabbitmq] -* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.spring-mvc[#production-ready-metrics-spring-mvc] -* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.system[#production-ready-metrics-system] -* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.timed-annotation[#production-ready-metrics-timed-annotation] -* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.tomcat[#production-ready-metrics-tomcat] -* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.spring-webflux[#production-ready-metrics-web-flux] -* xref:reference:actuator/monitoring.adoc#actuator.monitoring[#production-ready-monitoring] -* xref:reference:actuator/process-monitoring.adoc#actuator.process-monitoring[#production-ready-process-monitoring] -* xref:reference:actuator/process-monitoring.adoc#actuator.process-monitoring.configuration[#production-ready-process-monitoring-configuration] -* xref:reference:actuator/process-monitoring.adoc#actuator.process-monitoring.programmatically[#production-ready-process-monitoring-programmatically] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.health.reactive-health-indicators[#reactive-health-indicators] -* xref:reference:actuator/endpoints.adoc#actuator.endpoints.health.auto-configured-reactive-health-indicators[#reactive-health-indicators-autoconfigured] -* xref:reference:using/devtools.adoc#using.devtools.remote-applications.client[#running-remote-client-application] -* xref:build-tool-plugin:antlib.adoc#build-tool-plugins.antlib.tasks.exejar[#spring-boot-ant-exejar] -* xref:build-tool-plugin:antlib.adoc#build-tool-plugins.antlib.tasks.examples[#spring-boot-ant-exejar-examples] -* xref:build-tool-plugin:antlib.adoc#build-tool-plugins.antlib.findmainclass[#spring-boot-ant-findmainclass] -* xref:build-tool-plugin:antlib.adoc#build-tool-plugins.antlib.findmainclass.examples[#spring-boot-ant-findmainclass-examples] -* xref:build-tool-plugin:antlib.adoc#build-tool-plugins.antlib.tasks[#spring-boot-ant-tasks] -* xref:appendix:test-auto-configuration/index.adoc#appendix.test-auto-configuration[#test-auto-configuration] -* xref:appendix:test-auto-configuration/slices.adoc#appendix.test-auto-configuration.slices[#test-auto-configuration.slices] -* xref:reference:using/index.adoc#using[#using-boot] -* xref:reference:using/build-systems.adoc#using.build-systems.ant[#using-boot-ant] -* xref:reference:using/auto-configuration.adoc#using.auto-configuration[#using-boot-auto-configuration] -* xref:reference:using/build-systems.adoc#using.build-systems[#using-boot-build-systems] -* xref:reference:using/configuration-classes.adoc#using.configuration-classes[#using-boot-configuration-classes] -* xref:reference:using/build-systems.adoc#using.build-systems.dependency-management[#using-boot-dependency-management] -* xref:reference:using/devtools.adoc#using.devtools[#using-boot-devtools] -* xref:reference:using/devtools.adoc#using.devtools.restart.customizing-the-classload[#using-boot-devtools-customizing-classload] -* xref:reference:using/devtools.adoc#using.devtools.globalsettings[#using-boot-devtools-globalsettings] -* xref:reference:using/devtools.adoc#using.devtools.restart.limitations[#using-boot-devtools-known-restart-limitations] -* xref:reference:using/devtools.adoc#using.devtools.livereload[#using-boot-devtools-livereload] -* xref:reference:using/devtools.adoc#using.devtools.property-defaults[#using-boot-devtools-property-defaults] -* xref:reference:using/devtools.adoc#using.devtools.remote-applications[#using-boot-devtools-remote] -* xref:reference:using/devtools.adoc#using.devtools.remote-applications.update[#using-boot-devtools-remote-update] -* xref:reference:using/devtools.adoc#using.devtools.restart[#using-boot-devtools-restart] -* xref:reference:using/devtools.adoc#using.devtools.restart.watching-additional-paths[#using-boot-devtools-restart-additional-paths] -* xref:reference:using/devtools.adoc#using.devtools.restart.disable[#using-boot-devtools-restart-disable] -* xref:reference:using/devtools.adoc#using.devtools.restart.excluding-resources[#using-boot-devtools-restart-exclude] -* xref:reference:using/devtools.adoc#using.devtools.restart.logging-condition-delta[#using-boot-devtools-restart-logging-condition-delta] -* xref:reference:using/devtools.adoc#using.devtools.restart.triggerfile[#using-boot-devtools-restart-triggerfile] -* xref:reference:using/auto-configuration.adoc#using.auto-configuration.disabling-specific[#using-boot-disabling-specific-auto-configuration] -* xref:reference:using/running-your-application.adoc#using.running-your-application.hot-swapping[#using-boot-hot-swapping] -* xref:reference:using/configuration-classes.adoc#using.configuration-classes.importing-additional-configuration[#using-boot-importing-configuration] -* xref:reference:using/configuration-classes.adoc#using.configuration-classes.importing-xml-configuration[#using-boot-importing-xml-configuration] -* xref:reference:using/structuring-your-code.adoc#using.structuring-your-code.locating-the-main-class[#using-boot-locating-the-main-class] -* xref:reference:using/packaging-for-production.adoc#using.packaging-for-production[#using-boot-packaging-for-production] -* xref:reference:using/auto-configuration.adoc#using.auto-configuration.replacing[#using-boot-replacing-auto-configuration] -* xref:reference:using/running-your-application.adoc#using.running-your-application.as-a-packaged-application[#using-boot-running-as-a-packaged-application] -* xref:reference:using/running-your-application.adoc#using.running-your-application.from-an-ide[#using-boot-running-from-an-ide] -* xref:reference:using/running-your-application.adoc#using.running-your-application.with-the-gradle-plugin[#using-boot-running-with-the-gradle-plugin] -* xref:reference:using/running-your-application.adoc#using.running-your-application.with-the-maven-plugin[#using-boot-running-with-the-maven-plugin] -* xref:reference:using/running-your-application.adoc#using.running-your-application[#using-boot-running-your-application] -* xref:reference:using/spring-beans-and-dependency-injection.adoc#using.spring-beans-and-dependency-injection[#using-boot-spring-beans-and-dependency-injection] -* xref:reference:using/build-systems.adoc#using.build-systems.starters[#using-boot-starter] -* xref:reference:using/structuring-your-code.adoc#using.structuring-your-code[#using-boot-structuring-your-code] -* xref:reference:using/using-the-springbootapplication-annotation.adoc#using.using-the-springbootapplication-annotation[#using-boot-using-springbootapplication-annotation] -* xref:reference:using/structuring-your-code.adoc#using.structuring-your-code.using-the-default-package[#using-boot-using-the-default-package] -* xref:reference:using/devtools.adoc#using.devtools.restart.restart-vs-reload[#using-spring-boot-restart-vs-reload] +* xref:tutorial:first-application/index.adoc#getting-started.first-application.run[#getting-started-first-application-run] +* xref:tutorial:first-application/index.adoc#getting-started.first-application.run[#getting-started.first-application.run] +* xref:tutorial:first-application/index.adoc#getting-started.first-application[#getting-started-first-application] +* xref:tutorial:first-application/index.adoc#getting-started.first-application[#getting-started.first-application] +* xref:upgrading.adoc[#upgrading] +* xref:upgrading.adoc[upgrading] From 47b6f5a37cf0547d7db86e4760c89fba7d103118 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Dec 2024 20:43:42 +0000 Subject: [PATCH 044/203] Bump jfrog/setup-jfrog-cli from 4.4.2 to 4.4.3 Bumps [jfrog/setup-jfrog-cli](https://github.com/jfrog/setup-jfrog-cli) from 4.4.2 to 4.4.3. - [Release notes](https://github.com/jfrog/setup-jfrog-cli/releases) - [Commits](https://github.com/jfrog/setup-jfrog-cli/compare/18e785fb220d332edbf01964f853ff0fcaa22220...e7cc33a01bc1b1df406bac8a1c4a409a34bdca0a) --- updated-dependencies: - dependency-name: jfrog/setup-jfrog-cli dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] See gh-43355 --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 20cd4c5d0c7b..a77bd4779ac5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -78,7 +78,7 @@ jobs: runs-on: ${{ vars.UBUNTU_SMALL || 'ubuntu-latest' }} steps: - name: Set up JFrog CLI - uses: jfrog/setup-jfrog-cli@18e785fb220d332edbf01964f853ff0fcaa22220 # v4.4.2 + uses: jfrog/setup-jfrog-cli@e7cc33a01bc1b1df406bac8a1c4a409a34bdca0a # v4.4.3 env: JF_ENV_SPRING: ${{ vars.COMMERCIAL && secrets.COMMERCIAL_JF_ARTIFACTORY_SPRING || secrets.JF_ARTIFACTORY_SPRING }} - name: Promote open source build From a0e36c38da53540d38be8a683830ea550d582112 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Wed, 4 Dec 2024 07:49:10 +0100 Subject: [PATCH 045/203] Polish "Bump jfrog/setup-jfrog-cli from 4.4.2 to 4.4.3" See gh-43355 --- .github/actions/publish-gradle-plugin/action.yml | 2 +- .github/actions/sync-to-maven-central/action.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/publish-gradle-plugin/action.yml b/.github/actions/publish-gradle-plugin/action.yml index f3d7035f6f0a..f133cf321c04 100644 --- a/.github/actions/publish-gradle-plugin/action.yml +++ b/.github/actions/publish-gradle-plugin/action.yml @@ -21,7 +21,7 @@ runs: using: composite steps: - name: Set Up JFrog CLI - uses: jfrog/setup-jfrog-cli@18e785fb220d332edbf01964f853ff0fcaa22220 # v4.4.2 + uses: jfrog/setup-jfrog-cli@e7cc33a01bc1b1df406bac8a1c4a409a34bdca0a # v4.4.3 env: JF_ENV_SPRING: ${{ inputs.jfrog-cli-config-token }} - name: Download Artifacts diff --git a/.github/actions/sync-to-maven-central/action.yml b/.github/actions/sync-to-maven-central/action.yml index 7041f8d553bb..af148ddff542 100644 --- a/.github/actions/sync-to-maven-central/action.yml +++ b/.github/actions/sync-to-maven-central/action.yml @@ -20,7 +20,7 @@ runs: using: composite steps: - name: Set Up JFrog CLI - uses: jfrog/setup-jfrog-cli@18e785fb220d332edbf01964f853ff0fcaa22220 # v4.4.2 + uses: jfrog/setup-jfrog-cli@e7cc33a01bc1b1df406bac8a1c4a409a34bdca0a # v4.4.3 env: JF_ENV_SPRING: ${{ inputs.jfrog-cli-config-token }} - name: Download Release Artifacts From 3f17e42b38fba573cd3569e4213911d59ffe7c5c Mon Sep 17 00:00:00 2001 From: Yanming Zhou Date: Fri, 29 Nov 2024 11:25:47 +0800 Subject: [PATCH 046/203] Polish formatting of log configuration file 1. Remove space before `/>` to keep consistency. 2. Capitalize `filters` for Log4j2. 3. Uppercase log level to keep consistency. See gh-43322 --- .../boot/logging/log4j2/log4j2-file.xml | 24 +++++++++---------- .../boot/logging/log4j2/log4j2.xml | 24 +++++++++---------- .../boot/logging/logback/base.xml | 10 ++++---- .../boot/logging/logback/defaults.xml | 10 ++++---- .../src/test/resources/logback-broken.xml | 2 +- .../resources/logback-include-defaults.xml | 2 +- .../src/test/resources/logback-janino.xml | 2 +- .../src/test/resources/logback-nondefault.xml | 2 +- .../logback-springprofile-in-root.xml | 2 +- .../src/dockerTest/resources/logback.xml | 2 +- .../src/main/resources/log4j2.xml | 6 ++--- .../src/main/resources/logback.xml | 4 ++-- .../src/main/resources/logback-spring.xml | 6 ++--- 13 files changed, 48 insertions(+), 48 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/log4j2/log4j2-file.xml b/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/log4j2/log4j2-file.xml index 916f1126db61..e5e513dee2ea 100644 --- a/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/log4j2/log4j2-file.xml +++ b/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/log4j2/log4j2-file.xml @@ -20,22 +20,22 @@ - + - - - - - - - - - - - + + + + + + + + + + + diff --git a/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/log4j2/log4j2.xml b/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/log4j2/log4j2.xml index 239f2e35a34c..ee1044c36be1 100644 --- a/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/log4j2/log4j2.xml +++ b/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/log4j2/log4j2.xml @@ -10,22 +10,22 @@ - + - + - - - - - - - - - - + + + + + + + + + + diff --git a/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/logback/base.xml b/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/logback/base.xml index b1b17e289d92..04458c92a97e 100644 --- a/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/logback/base.xml +++ b/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/logback/base.xml @@ -5,12 +5,12 @@ Base logback configuration provided for compatibility with Spring Boot 1.1 --> - + - - + + - - + + diff --git a/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/logback/defaults.xml b/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/logback/defaults.xml index fa4006d2fc44..bad74fe1643d 100644 --- a/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/logback/defaults.xml +++ b/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/logback/defaults.xml @@ -5,11 +5,11 @@ Default logback configuration provided for import --> - - - - - + + + + + diff --git a/spring-boot-project/spring-boot/src/test/resources/logback-broken.xml b/spring-boot-project/spring-boot/src/test/resources/logback-broken.xml index 6411a145d452..7f8454941cff 100644 --- a/spring-boot-project/spring-boot/src/test/resources/logback-broken.xml +++ b/spring-boot-project/spring-boot/src/test/resources/logback-broken.xml @@ -6,6 +6,6 @@ - + diff --git a/spring-boot-project/spring-boot/src/test/resources/logback-include-defaults.xml b/spring-boot-project/spring-boot/src/test/resources/logback-include-defaults.xml index 76b3943cd2fc..0124d8a7e357 100644 --- a/spring-boot-project/spring-boot/src/test/resources/logback-include-defaults.xml +++ b/spring-boot-project/spring-boot/src/test/resources/logback-include-defaults.xml @@ -7,6 +7,6 @@ - + diff --git a/spring-boot-project/spring-boot/src/test/resources/logback-janino.xml b/spring-boot-project/spring-boot/src/test/resources/logback-janino.xml index 569b18e17ccb..5274e6f9693e 100644 --- a/spring-boot-project/spring-boot/src/test/resources/logback-janino.xml +++ b/spring-boot-project/spring-boot/src/test/resources/logback-janino.xml @@ -13,6 +13,6 @@ - + diff --git a/spring-boot-project/spring-boot/src/test/resources/logback-nondefault.xml b/spring-boot-project/spring-boot/src/test/resources/logback-nondefault.xml index da5f24ea1b11..5d1622c51841 100644 --- a/spring-boot-project/spring-boot/src/test/resources/logback-nondefault.xml +++ b/spring-boot-project/spring-boot/src/test/resources/logback-nondefault.xml @@ -6,6 +6,6 @@ - + diff --git a/spring-boot-project/spring-boot/src/test/resources/logback-springprofile-in-root.xml b/spring-boot-project/spring-boot/src/test/resources/logback-springprofile-in-root.xml index ea07eb8bd007..284c547a0b32 100644 --- a/spring-boot-project/spring-boot/src/test/resources/logback-springprofile-in-root.xml +++ b/spring-boot-project/spring-boot/src/test/resources/logback-springprofile-in-root.xml @@ -7,7 +7,7 @@ - + diff --git a/spring-boot-tests/spring-boot-integration-tests/spring-boot-launch-script-tests/src/dockerTest/resources/logback.xml b/spring-boot-tests/spring-boot-integration-tests/spring-boot-launch-script-tests/src/dockerTest/resources/logback.xml index 7c402db9a3fa..13e689a29304 100644 --- a/spring-boot-tests/spring-boot-integration-tests/spring-boot-launch-script-tests/src/dockerTest/resources/logback.xml +++ b/spring-boot-tests/spring-boot-integration-tests/spring-boot-launch-script-tests/src/dockerTest/resources/logback.xml @@ -5,6 +5,6 @@ - + diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-actuator-log4j2/src/main/resources/log4j2.xml b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-actuator-log4j2/src/main/resources/log4j2.xml index 1c84d286b093..238492a791c7 100644 --- a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-actuator-log4j2/src/main/resources/log4j2.xml +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-actuator-log4j2/src/main/resources/log4j2.xml @@ -10,9 +10,9 @@ - - - + + + diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-actuator/src/main/resources/logback.xml b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-actuator/src/main/resources/logback.xml index 5c19b4eed630..613cb692a5e3 100644 --- a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-actuator/src/main/resources/logback.xml +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-actuator/src/main/resources/logback.xml @@ -1,7 +1,7 @@ - + - + diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-logback/src/main/resources/logback-spring.xml b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-logback/src/main/resources/logback-spring.xml index 0a8ee5a84673..baf8bc039fc1 100644 --- a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-logback/src/main/resources/logback-spring.xml +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-logback/src/main/resources/logback-spring.xml @@ -1,8 +1,8 @@ - - + + - + From cc274ccdcab4700c765b0bcb19a14be634a50598 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Wed, 4 Dec 2024 10:33:58 +0100 Subject: [PATCH 047/203] Polish "Polish formatting of log configuration file" See gh-43322 --- .../src/test/resources/logback-without-extension | 2 +- .../boot/logging/logback/include-with-profile.xml | 2 +- .../boot/logging/logback/include-with-property.xml | 2 +- .../boot/logging/logback/multi-profile-names.xml | 4 ++-- .../org/springframework/boot/logging/logback/nested.xml | 4 ++-- .../boot/logging/logback/production-profile.xml | 4 ++-- .../boot/logging/logback/profile-expression.xml | 4 ++-- .../boot/logging/logback/profile-in-include.xml | 4 ++-- .../boot/logging/logback/property-default-value.xml | 2 +- .../springframework/boot/logging/logback/property-in-if.xml | 6 +++--- .../boot/logging/logback/property-in-include.xml | 4 ++-- .../org/springframework/boot/logging/logback/property.xml | 2 +- 12 files changed, 20 insertions(+), 20 deletions(-) diff --git a/spring-boot-project/spring-boot/src/test/resources/logback-without-extension b/spring-boot-project/spring-boot/src/test/resources/logback-without-extension index 68080b7c975b..1d55bbaf83fb 100644 --- a/spring-boot-project/spring-boot/src/test/resources/logback-without-extension +++ b/spring-boot-project/spring-boot/src/test/resources/logback-without-extension @@ -6,6 +6,6 @@ - + diff --git a/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/include-with-profile.xml b/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/include-with-profile.xml index 12772f0a3b27..231de8f580ae 100644 --- a/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/include-with-profile.xml +++ b/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/include-with-profile.xml @@ -1,5 +1,5 @@ - + \ No newline at end of file diff --git a/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/include-with-property.xml b/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/include-with-property.xml index c7e095d1596d..74f08edcb49e 100644 --- a/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/include-with-property.xml +++ b/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/include-with-property.xml @@ -1,3 +1,3 @@ - + \ No newline at end of file diff --git a/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/multi-profile-names.xml b/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/multi-profile-names.xml index 480897e67423..4f785c163a02 100644 --- a/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/multi-profile-names.xml +++ b/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/multi-profile-names.xml @@ -1,7 +1,7 @@ - + - + diff --git a/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/nested.xml b/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/nested.xml index 9ad8b0456803..247229cc0055 100644 --- a/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/nested.xml +++ b/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/nested.xml @@ -1,9 +1,9 @@ - + - + diff --git a/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/production-profile.xml b/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/production-profile.xml index 8b263afd5ddf..bb3c8aae3cba 100644 --- a/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/production-profile.xml +++ b/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/production-profile.xml @@ -1,7 +1,7 @@ - + - + diff --git a/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/profile-expression.xml b/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/profile-expression.xml index 448bb017a5e4..c11d7f9f6599 100644 --- a/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/profile-expression.xml +++ b/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/profile-expression.xml @@ -1,7 +1,7 @@ - + - + diff --git a/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/profile-in-include.xml b/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/profile-in-include.xml index 3c4c9ec17f6f..a03c5d926883 100644 --- a/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/profile-in-include.xml +++ b/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/profile-in-include.xml @@ -1,5 +1,5 @@ - - + + diff --git a/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/property-default-value.xml b/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/property-default-value.xml index dd00a99b875d..5fcf44025c48 100644 --- a/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/property-default-value.xml +++ b/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/property-default-value.xml @@ -1,6 +1,6 @@ - + diff --git a/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/property-in-if.xml b/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/property-in-if.xml index b16fde51f3e6..92bb19cd9e7b 100644 --- a/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/property-in-if.xml +++ b/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/property-in-if.xml @@ -1,10 +1,10 @@ - - + + - + diff --git a/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/property-in-include.xml b/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/property-in-include.xml index ca2c2705b4e8..f367385c99e3 100644 --- a/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/property-in-include.xml +++ b/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/property-in-include.xml @@ -1,5 +1,5 @@ - - + + diff --git a/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/property.xml b/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/property.xml index 15ef50ae3293..a574d13df7b2 100644 --- a/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/property.xml +++ b/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/property.xml @@ -1,6 +1,6 @@ - + From 7c7bb531b45edda5621dd1acb6a1e47491a2e881 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 4 Dec 2024 13:21:29 +0000 Subject: [PATCH 048/203] Improve handling of environment variables in failure analysis Prior to this change, the failure analysis for an invalid configuration property value filtered out the configuration property sources property source. This property source contains a "duplicate" of all of the environment's other property sources but with configuration property support (such as relaxed/fuzzy matching of environment variables). This was done to prevent the reporting of duplicates when a property was found in both the configuration property sources property source and the "normal" property sources. An unwanted side-effect of this was that fuzzy matching of environment variables was lost so the origin of com.example.some-property would be found in the environment variable was COM_EXAMPLE_SOME_PROPERTY but would not be found if it was COM_EXAMPLE_SOMEPROPERTY. This commit addresses this side-effect by no longer filtering out the configuration property sources property source. To then prevent duplicates from being reported in the analysis, it instead deduplicates things based on the origin of each property that's found in the environment's property sources. Fixes gh-43380 --- ...igurationPropertyValueFailureAnalyzer.java | 21 +++-- ...tionPropertyValueFailureAnalyzerTests.java | 83 ++++++++++++++++--- 2 files changed, 87 insertions(+), 17 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/InvalidConfigurationPropertyValueFailureAnalyzer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/InvalidConfigurationPropertyValueFailureAnalyzer.java index 9e2bd7a235d5..048024a44720 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/InvalidConfigurationPropertyValueFailureAnalyzer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/InvalidConfigurationPropertyValueFailureAnalyzer.java @@ -16,16 +16,18 @@ package org.springframework.boot.diagnostics.analyzer; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.stream.Stream; -import org.springframework.boot.context.properties.source.ConfigurationPropertySources; import org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException; import org.springframework.boot.diagnostics.AbstractFailureAnalyzer; import org.springframework.boot.diagnostics.FailureAnalysis; import org.springframework.boot.diagnostics.FailureAnalyzer; import org.springframework.boot.origin.Origin; import org.springframework.boot.origin.OriginLookup; +import org.springframework.boot.origin.PropertySourceOrigin; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.Environment; import org.springframework.core.env.PropertySource; @@ -61,18 +63,23 @@ protected FailureAnalysis analyze(Throwable rootFailure, InvalidConfigurationPro } private List getDescriptors(String propertyName) { + Set seen = new HashSet<>(); return getPropertySources().filter((source) -> source.containsProperty(propertyName)) .map((source) -> Descriptor.get(source, propertyName)) + .filter((descriptor) -> seen.add(getOrigin(descriptor))) .toList(); } - private Stream> getPropertySources() { - if (this.environment == null) { - return Stream.empty(); + private Origin getOrigin(Descriptor descriptor) { + Origin origin = descriptor.origin; + if (origin instanceof PropertySourceOrigin propertySourceOrigin) { + origin = propertySourceOrigin.getOrigin(); } - return this.environment.getPropertySources() - .stream() - .filter((source) -> !ConfigurationPropertySources.isAttachedConfigurationPropertySource(source)); + return origin; + } + + private Stream> getPropertySources() { + return (this.environment != null) ? this.environment.getPropertySources().stream() : Stream.empty(); } private void appendDetails(StringBuilder message, InvalidConfigurationPropertyValueException cause, diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/InvalidConfigurationPropertyValueFailureAnalyzerTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/InvalidConfigurationPropertyValueFailureAnalyzerTests.java index d50cd24c283b..df2b18b02da8 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/InvalidConfigurationPropertyValueFailureAnalyzerTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/InvalidConfigurationPropertyValueFailureAnalyzerTests.java @@ -20,13 +20,16 @@ import org.junit.jupiter.api.Test; +import org.springframework.boot.context.properties.source.ConfigurationPropertySources; import org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException; import org.springframework.boot.diagnostics.FailureAnalysis; import org.springframework.boot.origin.Origin; import org.springframework.boot.origin.OriginLookup; import org.springframework.core.env.EnumerablePropertySource; import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.SystemEnvironmentPropertySource; import org.springframework.mock.env.MockEnvironment; +import org.springframework.util.ObjectUtils; import static org.assertj.core.api.Assertions.assertThat; @@ -63,6 +66,26 @@ void analysisWithKnownProperty() { .doesNotContain("Additionally, this property is also set"); } + @Test + void analysisWithKnownPropertyFromSystemEnvironment() { + MapPropertySource source = new SystemEnvironmentPropertySource("systemEnvironment", + Collections.singletonMap("COM_EXAMPLE_TESTPROPERTY", "invalid")); + this.environment.getPropertySources().addFirst(source); + ConfigurationPropertySources.attach(this.environment); + assertThat(this.environment.getProperty("com.example.test-property")).isEqualTo("invalid"); + InvalidConfigurationPropertyValueException failure = new InvalidConfigurationPropertyValueException( + "com.example.test-property", "invalid", "This is not valid."); + FailureAnalysis analysis = performAnalysis(failure); + assertThat(analysis.getDescription()).contains("com.example.test-property") + .contains("invalid") + .contains("property source \"systemEnvironment\""); + assertThat(analysis.getCause()).isSameAs(failure); + assertThat(analysis.getAction()).contains("Review the value of the property with the provided reason."); + assertThat(analysis.getDescription()).contains("Validation failed for the following reason") + .contains("This is not valid.") + .doesNotContain("Additionally, this property is also set"); + } + @Test void analysisWithKnownPropertyAndNoReason() { MapPropertySource source = new MapPropertySource("test", Collections.singletonMap("test.property", "invalid")); @@ -84,6 +107,8 @@ void analysisWithKnownPropertyAndOtherCandidates() { this.environment.getPropertySources().addFirst(OriginCapablePropertySource.get(source)); this.environment.getPropertySources().addLast(additional); this.environment.getPropertySources().addLast(OriginCapablePropertySource.get(another)); + this.environment.getPropertySources().addLast(OriginCapablePropertySource.get("another-again", another)); + ConfigurationPropertySources.attach(this.environment); InvalidConfigurationPropertyValueException failure = new InvalidConfigurationPropertyValueException( "test.property", "invalid", "This is not valid."); FailureAnalysis analysis = performAnalysis(failure); @@ -92,7 +117,8 @@ void analysisWithKnownPropertyAndOtherCandidates() { assertThat(analysis.getDescription()) .contains("Additionally, this property is also set in the following property sources:") .contains("In 'additional' with the value 'valid'") - .contains("In 'another' with the value 'test' (originating from 'TestOrigin test.property')"); + .contains("In 'another' with the value 'test' (originating from 'TestOrigin test.property')") + .doesNotContain("another-again"); } @Test @@ -122,7 +148,11 @@ static class OriginCapablePropertySource extends EnumerablePropertySource private final EnumerablePropertySource propertySource; OriginCapablePropertySource(EnumerablePropertySource propertySource) { - super(propertySource.getName(), propertySource.getSource()); + this(propertySource.getName(), propertySource); + } + + OriginCapablePropertySource(String name, EnumerablePropertySource propertySource) { + super(name, propertySource.getSource()); this.propertySource = propertySource; } @@ -138,20 +168,53 @@ public String[] getPropertyNames() { @Override public Origin getOrigin(String name) { - return new Origin() { - - @Override - public String toString() { - return "TestOrigin " + name; - } - - }; + return new TestOrigin(name, this.propertySource.getName()); } static OriginCapablePropertySource get(EnumerablePropertySource propertySource) { return new OriginCapablePropertySource<>(propertySource); } + static OriginCapablePropertySource get(String name, EnumerablePropertySource propertySource) { + return new OriginCapablePropertySource<>(name, propertySource); + } + + static final class TestOrigin implements Origin { + + private final String name; + + private final String sourceName; + + private TestOrigin(String name, String sourceName) { + this.name = name; + this.sourceName = sourceName; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + TestOrigin other = (TestOrigin) obj; + return ObjectUtils.nullSafeEquals(this.name, other.name) + && ObjectUtils.nullSafeEquals(this.sourceName, other.sourceName); + } + + @Override + public int hashCode() { + return ObjectUtils.nullSafeHashCode(this.name); + } + + @Override + public String toString() { + return "TestOrigin " + this.name; + } + + } + } } From a696f29bbaebc4fa378720d29a27763cf447f929 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 4 Dec 2024 11:39:14 -0800 Subject: [PATCH 049/203] Upgrade to Native Build Tools Plugin 0.10.4 Closes gh-43385 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index fe79403935db..249e3ceec91d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -17,7 +17,7 @@ junitJupiterVersion=5.10.5 kotlinVersion=1.9.25 mavenVersion=3.9.4 mockitoVersion=5.11.0 -nativeBuildToolsVersion=0.10.3 +nativeBuildToolsVersion=0.10.4 snakeYamlVersion=2.2 springFrameworkVersion=6.1.15 springFramework60xVersion=6.0.23 From 0ebee1604399a8984b058ad916355a9502c4035c Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 4 Dec 2024 11:39:19 -0800 Subject: [PATCH 050/203] Upgrade to RxJava3 3.1.10 Closes gh-43386 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 90342193570f..81684d3ff258 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -1930,7 +1930,7 @@ bom { releaseNotes("https://github.com/rsocket/rsocket-java/releases/tag/{version}") } } - library("RxJava3", "3.1.9") { + library("RxJava3", "3.1.10") { group("io.reactivex.rxjava3") { modules = [ "rxjava" From 4c00c376a10aa8556d553f5a3016243f31a3b1d0 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 4 Dec 2024 11:39:23 -0800 Subject: [PATCH 051/203] Upgrade to Undertow 2.3.18.Final Closes gh-43387 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 81684d3ff258..c3ebc3f3a65c 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2467,7 +2467,7 @@ bom { releaseNotes("https://github.com/pingidentity/ldapsdk/releases/tag/{version}") } } - library("Undertow", "2.3.17.Final") { + library("Undertow", "2.3.18.Final") { group("io.undertow") { modules = [ "undertow-core", From c09f7c9944709c86139b8c327538dc87921c2423 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 4 Dec 2024 11:40:16 -0800 Subject: [PATCH 052/203] Start building against Micrometer 1.13.9 snapshots See gh-43388 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index c3ebc3f3a65c..6063ad57c91f 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -1415,7 +1415,7 @@ bom { releaseNotes("https://github.com/apache/maven-war-plugin/releases/tag/maven-war-plugin-{version}") } } - library("Micrometer", "1.13.8") { + library("Micrometer", "1.13.9-SNAPSHOT") { considerSnapshots() group("io.micrometer") { modules = [ From 53824c860aff2b932502adf46066436f00f3f67c Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 4 Dec 2024 11:40:20 -0800 Subject: [PATCH 053/203] Start building against Micrometer Tracing 1.3.7 snapshots See gh-43389 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 6063ad57c91f..af4596a4cf22 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -1439,7 +1439,7 @@ bom { releaseNotes("https://github.com/micrometer-metrics/micrometer/releases/tag/v{version}") } } - library("Micrometer Tracing", "1.3.6") { + library("Micrometer Tracing", "1.3.7-SNAPSHOT") { considerSnapshots() group("io.micrometer") { imports = [ From 740862a39b5ab998f2fc0738e64181793595435e Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 4 Dec 2024 11:40:24 -0800 Subject: [PATCH 054/203] Start building against Reactor Bom 2023.0.13 snapshots See gh-43390 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index af4596a4cf22..1a96d8d3addc 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -1891,7 +1891,7 @@ bom { ] } } - library("Reactor Bom", "2023.0.12") { + library("Reactor Bom", "2023.0.13-SNAPSHOT") { considerSnapshots() calendarName = "Reactor" group("io.projectreactor") { From cd3fd0e6daa11f688d2b46d4d13344671a9127e2 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 4 Dec 2024 11:40:29 -0800 Subject: [PATCH 055/203] Start building against Spring Authorization Server 1.3.4 snapshots See gh-43391 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 1a96d8d3addc..e7b06856fd42 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2113,7 +2113,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-amqp/releases/tag/v{version}") } } - library("Spring Authorization Server", "1.3.3") { + library("Spring Authorization Server", "1.3.4-SNAPSHOT") { considerSnapshots() group("org.springframework.security") { modules = [ From 6cd3ee5347dbe011cfcc46ff276d1dbc71bf6968 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 4 Dec 2024 11:40:33 -0800 Subject: [PATCH 056/203] Start building against Spring Data Bom 2024.0.7 snapshots See gh-43392 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index e7b06856fd42..209debc0ba3e 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2147,7 +2147,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-batch/releases/tag/v{version}") } } - library("Spring Data Bom", "2024.0.6") { + library("Spring Data Bom", "2024.0.7-SNAPSHOT") { considerSnapshots() calendarName = "Spring Data Release" group("org.springframework.data") { From d8804579fea8495665d7300d1baa42e16f8d84aa Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 4 Dec 2024 11:40:37 -0800 Subject: [PATCH 057/203] Start building against Spring Framework 6.1.16 snapshots See gh-43393 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 249e3ceec91d..2635deac6258 100644 --- a/gradle.properties +++ b/gradle.properties @@ -19,7 +19,7 @@ mavenVersion=3.9.4 mockitoVersion=5.11.0 nativeBuildToolsVersion=0.10.4 snakeYamlVersion=2.2 -springFrameworkVersion=6.1.15 +springFrameworkVersion=6.1.16-SNAPSHOT springFramework60xVersion=6.0.23 tomcatVersion=10.1.33 From 87612855577529597517b3f4cbd461491071d8c3 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 4 Dec 2024 11:40:41 -0800 Subject: [PATCH 058/203] Start building against Spring Kafka 3.2.6 snapshots See gh-43394 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 209debc0ba3e..0d74d05d6a78 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2233,7 +2233,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-integration/releases/tag/v{version}") } } - library("Spring Kafka", "3.2.5") { + library("Spring Kafka", "3.2.6-SNAPSHOT") { considerSnapshots() group("org.springframework.kafka") { modules = [ From f0fd24800ac1e3d6fc4ffdfc7790857b8f0e7533 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 4 Dec 2024 11:40:45 -0800 Subject: [PATCH 059/203] Start building against Spring LDAP 3.2.9 snapshots See gh-43395 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 0d74d05d6a78..2de1c5c09012 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2251,7 +2251,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-kafka/releases/tag/v{version}") } } - library("Spring LDAP", "3.2.8") { + library("Spring LDAP", "3.2.9-SNAPSHOT") { considerSnapshots() group("org.springframework.ldap") { modules = [ From 210c1465a2b3d7866eaa7217fba0b3fcda52267c Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 4 Dec 2024 11:40:50 -0800 Subject: [PATCH 060/203] Start building against Spring Pulsar 1.1.7 snapshots See gh-43396 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 2de1c5c09012..012a32e5ade6 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2271,7 +2271,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-ldap/releases/tag/{version}") } } - library("Spring Pulsar", "1.1.6") { + library("Spring Pulsar", "1.1.7-SNAPSHOT") { considerSnapshots() group("org.springframework.pulsar") { imports = [ From 1edc9974408856a23e75e309bed41099b9f5a125 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 4 Dec 2024 11:40:54 -0800 Subject: [PATCH 061/203] Start building against Spring Session 3.3.4 snapshots See gh-43397 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 012a32e5ade6..30c36a404f24 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2335,7 +2335,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-security/releases/tag/{version}") } } - library("Spring Session", "3.3.3") { + library("Spring Session", "3.3.4-SNAPSHOT") { considerSnapshots() prohibit { startsWith(["Apple-", "Bean-", "Corn-", "Dragonfruit-"]) From 7f8ccc66f711b6d7df69772a76089321b6049e95 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 4 Dec 2024 11:43:19 -0800 Subject: [PATCH 062/203] Upgrade to CycloneDX Maven Plugin 2.9.1 Closes gh-43398 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index a681ad30716f..f18d4cbc7ae6 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -273,7 +273,7 @@ bom { ] } } - library("CycloneDX Maven Plugin", "2.9.0") { + library("CycloneDX Maven Plugin", "2.9.1") { group("org.cyclonedx") { plugins = [ "cyclonedx-maven-plugin" From 79653a927558de07a7e5ea1ee1d0131725635ab6 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 4 Dec 2024 11:43:23 -0800 Subject: [PATCH 063/203] Upgrade to Elasticsearch Client 8.15.5 Closes gh-43399 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index f18d4cbc7ae6..47f2901355d3 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -337,7 +337,7 @@ bom { releaseNotes("https://github.com/ehcache/ehcache3/releases/tag/v{version}") } } - library("Elasticsearch Client", "8.15.4") { + library("Elasticsearch Client", "8.15.5") { group("org.elasticsearch.client") { modules = [ "elasticsearch-rest-client" { From a538b8bef42c9e336a6605288db59bf88c6839c2 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 4 Dec 2024 11:43:27 -0800 Subject: [PATCH 064/203] Upgrade to Hibernate 6.6.3.Final Closes gh-43400 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 47f2901355d3..c54e8edebf03 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -514,7 +514,7 @@ bom { releaseNotes("https://github.com/hazelcast/hazelcast/releases/tag/v{version}") } } - library("Hibernate", "6.6.2.Final") { + library("Hibernate", "6.6.3.Final") { group("org.hibernate.orm") { modules = [ "hibernate-agroal", From cf321b15c43c40d2e5bdf442fbe1de53584dc4b9 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 4 Dec 2024 11:43:32 -0800 Subject: [PATCH 065/203] Upgrade to Jackson Bom 2.18.2 Closes gh-43401 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 813f112d99db..b4b045ed5e26 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,7 +11,7 @@ checkstyleToolVersion=10.12.4 commonsCodecVersion=1.17.1 graalVersion=22.3 hamcrestVersion=2.2 -jacksonVersion=2.18.1 +jacksonVersion=2.18.2 javaFormatVersion=0.0.43 junitJupiterVersion=5.11.3 kotlinVersion=1.9.25 From 3010d7a4714ffa14383a23bfe3825901202ec4fc Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 4 Dec 2024 11:43:36 -0800 Subject: [PATCH 066/203] Upgrade to Log4j2 2.24.2 Closes gh-43402 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index c54e8edebf03..e023947f48d8 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -1217,7 +1217,7 @@ bom { releaseNotes("https://github.com/liquibase/liquibase/releases/tag/v{version}") } } - library("Log4j2", "2.24.1") { + library("Log4j2", "2.24.2") { group("org.apache.logging.log4j") { imports = [ "log4j-bom" From 008e4a0cd47af10c73e9d252846d5507908de7c6 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 4 Dec 2024 11:43:40 -0800 Subject: [PATCH 067/203] Upgrade to Native Build Tools Plugin 0.10.4 Closes gh-43403 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index b4b045ed5e26..2277b12e4cd9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -17,7 +17,7 @@ junitJupiterVersion=5.11.3 kotlinVersion=1.9.25 mavenVersion=3.9.4 mockitoVersion=5.14.2 -nativeBuildToolsVersion=0.10.3 +nativeBuildToolsVersion=0.10.4 snakeYamlVersion=2.3 springFrameworkVersion=6.2.0 springFramework60xVersion=6.0.23 From 060f89e19573062afadc8666144f6605247ab7be Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 4 Dec 2024 11:43:44 -0800 Subject: [PATCH 068/203] Upgrade to Prometheus Client 1.3.4 Closes gh-43404 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index e023947f48d8..2c7dd587a3ef 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -1676,7 +1676,7 @@ bom { releaseNotes("https://github.com/pgjdbc/pgjdbc/releases/tag/REL{version}") } } - library("Prometheus Client", "1.3.3") { + library("Prometheus Client", "1.3.4") { group("io.prometheus") { imports = [ "prometheus-metrics-bom" From 002539f6f6b2c0953b55c9dddb3ea2156c444e64 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 4 Dec 2024 11:43:48 -0800 Subject: [PATCH 069/203] Upgrade to Pulsar 3.3.3 Closes gh-43405 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 2c7dd587a3ef..6e221e091f51 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -1700,7 +1700,7 @@ bom { releaseNotes("https://github.com/prometheus/client_java/releases/tag/parent-{version}") } } - library("Pulsar", "3.3.2") { + library("Pulsar", "3.3.3") { group("org.apache.pulsar") { imports = [ "pulsar-bom" From ecd73478ca089d5a362b908c1fd5875d75771a1f Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 4 Dec 2024 11:43:52 -0800 Subject: [PATCH 070/203] Upgrade to RxJava3 3.1.10 Closes gh-43406 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 6e221e091f51..ec54344f6d22 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -1913,7 +1913,7 @@ bom { releaseNotes("https://github.com/rsocket/rsocket-java/releases/tag/{version}") } } - library("RxJava3", "3.1.9") { + library("RxJava3", "3.1.10") { group("io.reactivex.rxjava3") { modules = [ "rxjava" From e431b119a571b15f1a2ac80396ca7e81f5102565 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 4 Dec 2024 11:43:56 -0800 Subject: [PATCH 071/203] Upgrade to SQLite JDBC 3.47.1.0 Closes gh-43407 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index ec54344f6d22..00d58a1b22e2 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2356,7 +2356,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-ws/releases/tag/v{version}") } } - library("SQLite JDBC", "3.47.0.0") { + library("SQLite JDBC", "3.47.1.0") { group("org.xerial") { modules = [ "sqlite-jdbc" From e42095813ab3ddd21f183e57e34cb50d6e4ffc90 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 4 Dec 2024 11:48:10 -0800 Subject: [PATCH 072/203] Start building against Micrometer 1.14.2 snapshots See gh-43408 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 00d58a1b22e2..92dd6b5dad71 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -1440,7 +1440,7 @@ bom { releaseNotes("https://github.com/apache/maven-war-plugin/releases/tag/maven-war-plugin-{version}") } } - library("Micrometer", "1.14.1") { + library("Micrometer", "1.14.2-SNAPSHOT") { considerSnapshots() group("io.micrometer") { modules = [ From bece4f51bbb524e83191892cbe000cf8894a69f3 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 4 Dec 2024 11:48:15 -0800 Subject: [PATCH 073/203] Start building against Micrometer Tracing 1.4.1 snapshots See gh-43409 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 92dd6b5dad71..356b2f6cbe85 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -1464,7 +1464,7 @@ bom { releaseNotes("https://github.com/micrometer-metrics/micrometer/releases/tag/v{version}") } } - library("Micrometer Tracing", "1.4.0") { + library("Micrometer Tracing", "1.4.1-SNAPSHOT") { considerSnapshots() group("io.micrometer") { imports = [ From 41aa90f036474bd20da54305c4205eacd4806cea Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 4 Dec 2024 11:48:19 -0800 Subject: [PATCH 074/203] Start building against Reactor Bom 2024.0.1 snapshots See gh-43410 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 356b2f6cbe85..b7af739f0952 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -1874,7 +1874,7 @@ bom { ] } } - library("Reactor Bom", "2024.0.0") { + library("Reactor Bom", "2024.0.1-SNAPSHOT") { considerSnapshots() calendarName = "Reactor" group("io.projectreactor") { From e91d0da022f5b381570c605beb72f18fd9836920 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 4 Dec 2024 11:48:23 -0800 Subject: [PATCH 075/203] Start building against Spring AMQP 3.2.1 snapshots See gh-43411 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index b7af739f0952..239780917829 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2079,7 +2079,7 @@ bom { ] } } - library("Spring AMQP", "3.2.0") { + library("Spring AMQP", "3.2.1-SNAPSHOT") { considerSnapshots() group("org.springframework.amqp") { imports = [ From 4f914ab95101d8de4c2d332a010b83fe6b165e35 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 4 Dec 2024 11:48:27 -0800 Subject: [PATCH 076/203] Start building against Spring Authorization Server 1.4.1 snapshots See gh-43412 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 239780917829..af9b4ae0c85b 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2096,7 +2096,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-amqp/releases/tag/v{version}") } } - library("Spring Authorization Server", "1.4.0") { + library("Spring Authorization Server", "1.4.1-SNAPSHOT") { considerSnapshots() group("org.springframework.security") { modules = [ From e8e46297916734ceaa24fec31160dfb5f8882098 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 4 Dec 2024 11:48:31 -0800 Subject: [PATCH 077/203] Start building against Spring Data Bom 2024.1.1 snapshots See gh-43413 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index af9b4ae0c85b..6c85b78d384c 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2130,7 +2130,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-batch/releases/tag/v{version}") } } - library("Spring Data Bom", "2024.1.0") { + library("Spring Data Bom", "2024.1.1-SNAPSHOT") { considerSnapshots() calendarName = "Spring Data Release" group("org.springframework.data") { From d964b86e1b51d12ead9542cc6386f347c8bcfc49 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 4 Dec 2024 11:48:35 -0800 Subject: [PATCH 078/203] Start building against Spring Framework 6.2.1 snapshots See gh-43414 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 2277b12e4cd9..adc886a5a0c1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -19,7 +19,7 @@ mavenVersion=3.9.4 mockitoVersion=5.14.2 nativeBuildToolsVersion=0.10.4 snakeYamlVersion=2.3 -springFrameworkVersion=6.2.0 +springFrameworkVersion=6.2.1-SNAPSHOT springFramework60xVersion=6.0.23 tomcatVersion=10.1.33 From 32532b1f4d9100803c11bb557cf4f84a75fee3f1 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 4 Dec 2024 11:48:39 -0800 Subject: [PATCH 079/203] Start building against Spring Integration 6.4.1 snapshots See gh-43415 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 6c85b78d384c..b5c31c8e3f0a 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2199,7 +2199,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-hateoas/releases/tag/{version}") } } - library("Spring Integration", "6.4.0") { + library("Spring Integration", "6.4.1-SNAPSHOT") { considerSnapshots() group("org.springframework.integration") { imports = [ From 49df76a45d4ad4bed47cd12ff2aa8132165df94b Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 4 Dec 2024 11:48:43 -0800 Subject: [PATCH 080/203] Start building against Spring Kafka 3.3.1 snapshots See gh-43416 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index b5c31c8e3f0a..bbeb68df797a 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2216,7 +2216,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-integration/releases/tag/v{version}") } } - library("Spring Kafka", "3.3.0") { + library("Spring Kafka", "3.3.1-SNAPSHOT") { considerSnapshots() group("org.springframework.kafka") { modules = [ From bcf9e6c513d34d853f181bd9a2c29c1b022f90b0 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 4 Dec 2024 11:48:47 -0800 Subject: [PATCH 081/203] Start building against Spring LDAP 3.2.9 snapshots See gh-43417 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index bbeb68df797a..ca8e7928cd28 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2234,7 +2234,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-kafka/releases/tag/v{version}") } } - library("Spring LDAP", "3.2.8") { + library("Spring LDAP", "3.2.9-SNAPSHOT") { considerSnapshots() group("org.springframework.ldap") { modules = [ From 7852284d59f528065b8f312f41b620d839bf6be8 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 4 Dec 2024 11:48:51 -0800 Subject: [PATCH 082/203] Start building against Spring Pulsar 1.2.1 snapshots See gh-43418 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index ca8e7928cd28..2f8001da5657 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2254,7 +2254,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-ldap/releases/tag/{version}") } } - library("Spring Pulsar", "1.2.0") { + library("Spring Pulsar", "1.2.1-SNAPSHOT") { considerSnapshots() group("org.springframework.pulsar") { imports = [ From c7882d13960c9f64a3a60096969095c4ca5c2e0a Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 4 Dec 2024 11:48:55 -0800 Subject: [PATCH 083/203] Start building against Spring Security 6.4.2 snapshots See gh-43419 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 2f8001da5657..51ff617d8748 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2301,7 +2301,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-retry/releases/tag/v{version}") } } - library("Spring Security", "6.4.1") { + library("Spring Security", "6.4.2-SNAPSHOT") { considerSnapshots() group("org.springframework.security") { imports = [ From c1f0dacd3f42a4fb1aabdf8bf658335663912dae Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 4 Dec 2024 11:48:59 -0800 Subject: [PATCH 084/203] Start building against Spring Session 3.4.1 snapshots See gh-43420 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 51ff617d8748..d59d3ed7abbb 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2318,7 +2318,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-security/releases/tag/{version}") } } - library("Spring Session", "3.4.0") { + library("Spring Session", "3.4.1-SNAPSHOT") { considerSnapshots() prohibit { startsWith(["Apple-", "Bean-", "Corn-", "Dragonfruit-"]) From 9e7972a9b4be9035f91609ea72299512c0daec09 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 4 Dec 2024 13:54:28 -0800 Subject: [PATCH 085/203] Polish code with code cleanup rules --- .../orm/jpa/HibernateJpaConfiguration.java | 4 +-- .../orm/jpa/HibernateProperties.java | 20 +++++++------ ...eOAuth2ResourceServerJwkConfiguration.java | 11 ++++++-- .../OAuth2ResourceServerJwtConfiguration.java | 11 ++++++-- .../GroovyTemplateAutoConfigurationTests.java | 2 +- .../orm/jpa/HibernatePropertiesTests.java | 28 ++++++++++--------- .../pulsar/PulsarConfigurationTests.java | 4 +-- .../validation/ValidatorAdapterTests.java | 2 +- .../mock/mockito/MockitoPostProcessor.java | 2 +- .../web/client/TestRestTemplateTests.java | 4 +-- .../boot/loader/jar/StringSequence.java | 1 + .../UndertowServletWebServerFactory.java | 2 +- .../AbstractFilterRegistrationBeanTests.java | 3 +- .../ui/SampleActuatorUiApplicationTests.java | 4 +-- .../SampleServletApplicationTests.java | 2 +- .../SampleMethodSecurityApplicationTests.java | 6 ++-- ...SampleWebSecureCustomApplicationTests.java | 6 ++-- .../SampleWebSecureJdbcApplicationTests.java | 6 ++-- .../SampleWebSecureApplicationTests.java | 8 +++--- 19 files changed, 72 insertions(+), 54 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.java index d402c764822a..913d32cfa890 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.java @@ -32,7 +32,7 @@ import org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy; import org.hibernate.boot.model.naming.ImplicitNamingStrategy; import org.hibernate.boot.model.naming.PhysicalNamingStrategy; -import org.hibernate.cfg.AvailableSettings; +import org.hibernate.cfg.ManagedBeanSettings; import org.springframework.aot.hint.MemberCategory; import org.springframework.aot.hint.RuntimeHints; @@ -121,7 +121,7 @@ private List determineHibernatePropertiesCustomiz List customizers = new ArrayList<>(); if (ClassUtils.isPresent("org.hibernate.resource.beans.container.spi.BeanContainer", getClass().getClassLoader())) { - customizers.add((properties) -> properties.put(AvailableSettings.BEAN_CONTAINER, + customizers.add((properties) -> properties.put(ManagedBeanSettings.BEAN_CONTAINER, new SpringBeanContainer(beanFactory))); } if (physicalNamingStrategy != null || implicitNamingStrategy != null) { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateProperties.java index d35e6f41046f..c01450b1e55e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateProperties.java @@ -22,7 +22,9 @@ import java.util.function.Supplier; import org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy; -import org.hibernate.cfg.AvailableSettings; +import org.hibernate.cfg.MappingSettings; +import org.hibernate.cfg.PersistenceSettings; +import org.hibernate.cfg.SchemaToolingSettings; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy; @@ -86,10 +88,10 @@ private Map getAdditionalProperties(Map existing getNaming().applyNamingStrategies(result); String ddlAuto = determineDdlAuto(existing, settings::getDdlAuto); if (StringUtils.hasText(ddlAuto) && !"none".equals(ddlAuto)) { - result.put(AvailableSettings.HBM2DDL_AUTO, ddlAuto); + result.put(SchemaToolingSettings.HBM2DDL_AUTO, ddlAuto); } else { - result.remove(AvailableSettings.HBM2DDL_AUTO); + result.remove(SchemaToolingSettings.HBM2DDL_AUTO); } Collection customizers = settings.getHibernatePropertiesCustomizers(); if (!ObjectUtils.isEmpty(customizers)) { @@ -99,20 +101,20 @@ private Map getAdditionalProperties(Map existing } private void applyScanner(Map result) { - if (!result.containsKey(AvailableSettings.SCANNER) && ClassUtils.isPresent(DISABLED_SCANNER_CLASS, null)) { - result.put(AvailableSettings.SCANNER, DISABLED_SCANNER_CLASS); + if (!result.containsKey(PersistenceSettings.SCANNER) && ClassUtils.isPresent(DISABLED_SCANNER_CLASS, null)) { + result.put(PersistenceSettings.SCANNER, DISABLED_SCANNER_CLASS); } } private String determineDdlAuto(Map existing, Supplier defaultDdlAuto) { - String ddlAuto = existing.get(AvailableSettings.HBM2DDL_AUTO); + String ddlAuto = existing.get(SchemaToolingSettings.HBM2DDL_AUTO); if (ddlAuto != null) { return ddlAuto; } if (this.ddlAuto != null) { return this.ddlAuto; } - if (existing.get(AvailableSettings.JAKARTA_HBM2DDL_DATABASE_ACTION) != null) { + if (existing.get(SchemaToolingSettings.JAKARTA_HBM2DDL_DATABASE_ACTION) != null) { return null; } return defaultDdlAuto.get(); @@ -147,9 +149,9 @@ public void setPhysicalStrategy(String physicalStrategy) { } private void applyNamingStrategies(Map properties) { - applyNamingStrategy(properties, AvailableSettings.IMPLICIT_NAMING_STRATEGY, this.implicitStrategy, + applyNamingStrategy(properties, MappingSettings.IMPLICIT_NAMING_STRATEGY, this.implicitStrategy, SpringImplicitNamingStrategy.class::getName); - applyNamingStrategy(properties, AvailableSettings.PHYSICAL_NAMING_STRATEGY, this.physicalStrategy, + applyNamingStrategy(properties, MappingSettings.PHYSICAL_NAMING_STRATEGY, this.physicalStrategy, CamelCaseToUnderscoresNamingStrategy.class::getName); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerJwkConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerJwkConfiguration.java index 5cd528044e47..5d592a98e4be 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerJwkConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerJwkConfiguration.java @@ -115,13 +115,20 @@ private OAuth2TokenValidator getValidators(OAuth2TokenValidator defaul List> validators = new ArrayList<>(); validators.add(defaultValidator); if (!CollectionUtils.isEmpty(audiences)) { - validators.add(new JwtClaimValidator>(JwtClaimNames.AUD, - (aud) -> aud != null && !Collections.disjoint(aud, audiences))); + validators.add(audValidator(audiences)); } validators.addAll(this.additionalValidators); return new DelegatingOAuth2TokenValidator<>(validators); } + private JwtClaimValidator> audValidator(List audiences) { + return new JwtClaimValidator<>(JwtClaimNames.AUD, (aud) -> nullSafeDisjoint(aud, audiences)); + } + + private boolean nullSafeDisjoint(List c1, List c2) { + return c1 != null && !Collections.disjoint(c1, c2); + } + @Bean @Conditional(KeyValueCondition.class) NimbusReactiveJwtDecoder jwtDecoderByPublicKeyValue() throws Exception { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwtConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwtConfiguration.java index c3e20f9841a6..f191a8173cc9 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwtConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwtConfiguration.java @@ -114,13 +114,20 @@ private OAuth2TokenValidator getValidators(OAuth2TokenValidator defaul List> validators = new ArrayList<>(); validators.add(defaultValidator); if (!CollectionUtils.isEmpty(audiences)) { - validators.add(new JwtClaimValidator>(JwtClaimNames.AUD, - (aud) -> aud != null && !Collections.disjoint(aud, audiences))); + validators.add(audValidator(audiences)); } validators.addAll(this.additionalValidators); return new DelegatingOAuth2TokenValidator<>(validators); } + private JwtClaimValidator> audValidator(List audiences) { + return new JwtClaimValidator<>(JwtClaimNames.AUD, (aud) -> nullSafeDisjoint(aud, audiences)); + } + + private boolean nullSafeDisjoint(List c1, List c2) { + return c1 != null && !Collections.disjoint(c1, c2); + } + @Bean @Conditional(KeyValueCondition.class) JwtDecoder jwtDecoderByPublicKeyValue() throws Exception { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/groovy/template/GroovyTemplateAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/groovy/template/GroovyTemplateAutoConfigurationTests.java index ddea016a6ff5..85d96c607917 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/groovy/template/GroovyTemplateAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/groovy/template/GroovyTemplateAutoConfigurationTests.java @@ -162,7 +162,7 @@ void renderTemplate() throws Exception { MarkupTemplateEngine engine = config.getTemplateEngine(); Writer writer = new StringWriter(); engine.createTemplate(new ClassPathResource("templates/message.tpl").getFile()) - .make(new HashMap(Collections.singletonMap("greeting", "Hello World"))) + .make(new HashMap<>(Collections.singletonMap("greeting", "Hello World"))) .writeTo(writer); assertThat(writer.toString()).contains("Hello World"); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernatePropertiesTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernatePropertiesTests.java index 1e67d73cac39..d095e367b1a2 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernatePropertiesTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernatePropertiesTests.java @@ -21,7 +21,9 @@ import java.util.function.Supplier; import org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy; -import org.hibernate.cfg.AvailableSettings; +import org.hibernate.cfg.MappingSettings; +import org.hibernate.cfg.PersistenceSettings; +import org.hibernate.cfg.SchemaToolingSettings; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; @@ -59,9 +61,9 @@ class HibernatePropertiesTests { void noCustomNamingStrategy() { this.contextRunner.run(assertHibernateProperties((hibernateProperties) -> { assertThat(hibernateProperties).doesNotContainKeys("hibernate.ejb.naming_strategy"); - assertThat(hibernateProperties).containsEntry(AvailableSettings.PHYSICAL_NAMING_STRATEGY, + assertThat(hibernateProperties).containsEntry(MappingSettings.PHYSICAL_NAMING_STRATEGY, CamelCaseToUnderscoresNamingStrategy.class.getName()); - assertThat(hibernateProperties).containsEntry(AvailableSettings.IMPLICIT_NAMING_STRATEGY, + assertThat(hibernateProperties).containsEntry(MappingSettings.IMPLICIT_NAMING_STRATEGY, SpringImplicitNamingStrategy.class.getName()); })); } @@ -73,8 +75,8 @@ void hibernate5CustomNamingStrategies() { "spring.jpa.hibernate.naming.physical-strategy:com.example.Physical") .run(assertHibernateProperties((hibernateProperties) -> { assertThat(hibernateProperties).contains( - entry(AvailableSettings.IMPLICIT_NAMING_STRATEGY, "com.example.Implicit"), - entry(AvailableSettings.PHYSICAL_NAMING_STRATEGY, "com.example.Physical")); + entry(MappingSettings.IMPLICIT_NAMING_STRATEGY, "com.example.Implicit"), + entry(MappingSettings.PHYSICAL_NAMING_STRATEGY, "com.example.Physical")); assertThat(hibernateProperties).doesNotContainKeys("hibernate.ejb.naming_strategy"); })); } @@ -87,8 +89,8 @@ void hibernate5CustomNamingStrategiesViaJpaProperties() { .run(assertHibernateProperties((hibernateProperties) -> { // You can override them as we don't provide any default assertThat(hibernateProperties).contains( - entry(AvailableSettings.IMPLICIT_NAMING_STRATEGY, "com.example.Implicit"), - entry(AvailableSettings.PHYSICAL_NAMING_STRATEGY, "com.example.Physical")); + entry(MappingSettings.IMPLICIT_NAMING_STRATEGY, "com.example.Implicit"), + entry(MappingSettings.PHYSICAL_NAMING_STRATEGY, "com.example.Physical")); assertThat(hibernateProperties).doesNotContainKeys("hibernate.ejb.naming_strategy"); })); } @@ -96,15 +98,15 @@ void hibernate5CustomNamingStrategiesViaJpaProperties() { @Test void scannerUsesDisabledScannerByDefault() { this.contextRunner.run(assertHibernateProperties((hibernateProperties) -> assertThat(hibernateProperties) - .containsEntry(AvailableSettings.SCANNER, "org.hibernate.boot.archive.scan.internal.DisabledScanner"))); + .containsEntry(PersistenceSettings.SCANNER, "org.hibernate.boot.archive.scan.internal.DisabledScanner"))); } @Test void scannerCanBeCustomized() { this.contextRunner.withPropertyValues( "spring.jpa.properties.hibernate.archive.scanner:org.hibernate.boot.archive.scan.internal.StandardScanner") - .run(assertHibernateProperties((hibernateProperties) -> assertThat(hibernateProperties) - .containsEntry(AvailableSettings.SCANNER, "org.hibernate.boot.archive.scan.internal.StandardScanner"))); + .run(assertHibernateProperties((hibernateProperties) -> assertThat(hibernateProperties).containsEntry( + PersistenceSettings.SCANNER, "org.hibernate.boot.archive.scan.internal.StandardScanner"))); } @Test @@ -125,8 +127,8 @@ void defaultDdlAutoIsNotInvokedAndDdlAutoIsNotSetIfJpaDbActionPropertyIsSet() { .withPropertyValues( "spring.jpa.properties.jakarta.persistence.schema-generation.database.action=drop-and-create") .run(assertHibernateProperties((hibernateProperties) -> { - assertThat(hibernateProperties).doesNotContainKey(AvailableSettings.HBM2DDL_AUTO); - assertThat(hibernateProperties).containsEntry(AvailableSettings.JAKARTA_HBM2DDL_DATABASE_ACTION, + assertThat(hibernateProperties).doesNotContainKey(SchemaToolingSettings.HBM2DDL_AUTO); + assertThat(hibernateProperties).containsEntry(SchemaToolingSettings.JAKARTA_HBM2DDL_DATABASE_ACTION, "drop-and-create"); then(this.ddlAutoSupplier).should(never()).get(); })); @@ -134,7 +136,7 @@ void defaultDdlAutoIsNotInvokedAndDdlAutoIsNotSetIfJpaDbActionPropertyIsSet() { private ContextConsumer assertDefaultDdlAutoNotInvoked(String expectedDdlAuto) { return assertHibernateProperties((hibernateProperties) -> { - assertThat(hibernateProperties).containsEntry(AvailableSettings.HBM2DDL_AUTO, expectedDdlAuto); + assertThat(hibernateProperties).containsEntry(SchemaToolingSettings.HBM2DDL_AUTO, expectedDdlAuto); then(this.ddlAutoSupplier).should(never()).get(); }); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/pulsar/PulsarConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/pulsar/PulsarConfigurationTests.java index ef775cab6336..01458262b4b5 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/pulsar/PulsarConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/pulsar/PulsarConfigurationTests.java @@ -34,8 +34,8 @@ import org.assertj.core.api.MapAssert; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.mockito.ArgumentMatchers; import org.mockito.InOrder; -import org.mockito.Mockito; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.TestConfiguration; @@ -143,7 +143,7 @@ void whenHasUserDefinedFailoverPropertiesAddsToClient() { .getField(clientFactory, "customizer"); customizeAction.accept(pulsarClientBuilderCustomizer, target); InOrder ordered = inOrder(target); - ordered.verify(target).serviceUrlProvider(Mockito.any(AutoClusterFailover.class)); + ordered.verify(target).serviceUrlProvider(ArgumentMatchers.any(AutoClusterFailover.class)); assertThat(pulsarProperties.getClient().getFailover().getDelay()).isEqualTo(Duration.ofSeconds(15)); assertThat(pulsarProperties.getClient().getFailover().getSwitchBackDelay()) .isEqualTo(Duration.ofSeconds(30)); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/validation/ValidatorAdapterTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/validation/ValidatorAdapterTests.java index 641c45dc220f..8a3cb76bc80a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/validation/ValidatorAdapterTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/validation/ValidatorAdapterTests.java @@ -56,7 +56,7 @@ void wrapLocalValidatorFactoryBean() { this.contextRunner.withUserConfiguration(LocalValidatorFactoryBeanConfig.class).run((context) -> { ValidatorAdapter wrapper = context.getBean(ValidatorAdapter.class); assertThat(wrapper.supports(SampleData.class)).isTrue(); - MapBindingResult errors = new MapBindingResult(new HashMap(), "test"); + MapBindingResult errors = new MapBindingResult(new HashMap<>(), "test"); wrapper.validate(new SampleData(40), errors); assertThat(errors.getErrorCount()).isOne(); }); diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockitoPostProcessor.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockitoPostProcessor.java index cb7dee345008..b886f179968e 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockitoPostProcessor.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockitoPostProcessor.java @@ -421,7 +421,7 @@ private static BeanDefinition getOrAddBeanDefinition(BeanDefinitionRegistry regi RootBeanDefinition definition = new RootBeanDefinition(postProcessor); definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); ConstructorArgumentValues constructorArguments = definition.getConstructorArgumentValues(); - constructorArguments.addIndexedArgumentValue(0, new LinkedHashSet()); + constructorArguments.addIndexedArgumentValue(0, new LinkedHashSet<>()); registry.registerBeanDefinition(BEAN_NAME, definition); return definition; } diff --git a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/web/client/TestRestTemplateTests.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/web/client/TestRestTemplateTests.java index 022000e0be36..8d5ba9c055e2 100644 --- a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/web/client/TestRestTemplateTests.java +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/web/client/TestRestTemplateTests.java @@ -270,13 +270,13 @@ void deleteHandlesRelativeUris() throws IOException { @Test void exchangeWithRequestEntityAndClassHandlesRelativeUris() throws IOException { verifyRelativeUriHandling((testRestTemplate, relativeUri) -> testRestTemplate - .exchange(new RequestEntity(HttpMethod.GET, relativeUri), String.class)); + .exchange(new RequestEntity<>(HttpMethod.GET, relativeUri), String.class)); } @Test void exchangeWithRequestEntityAndParameterizedTypeReferenceHandlesRelativeUris() throws IOException { verifyRelativeUriHandling((testRestTemplate, relativeUri) -> testRestTemplate - .exchange(new RequestEntity(HttpMethod.GET, relativeUri), new ParameterizedTypeReference() { + .exchange(new RequestEntity<>(HttpMethod.GET, relativeUri), new ParameterizedTypeReference() { })); } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader-classic/src/main/java/org/springframework/boot/loader/jar/StringSequence.java b/spring-boot-project/spring-boot-tools/spring-boot-loader-classic/src/main/java/org/springframework/boot/loader/jar/StringSequence.java index 12850a4ebe3e..69ae7d6cae7f 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-loader-classic/src/main/java/org/springframework/boot/loader/jar/StringSequence.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader-classic/src/main/java/org/springframework/boot/loader/jar/StringSequence.java @@ -76,6 +76,7 @@ public StringSequence subSequence(int start, int end) { * Returns {@code true} if the sequence is empty. Public to be compatible with JDK 15. * @return {@code true} if {@link #length()} is {@code 0}, otherwise {@code false} */ + @Override public boolean isEmpty() { return length() == 0; } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowServletWebServerFactory.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowServletWebServerFactory.java index e03d06717ba2..67f42a247bec 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowServletWebServerFactory.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowServletWebServerFactory.java @@ -369,7 +369,7 @@ private void registerServletContainerInitializerToDriveServletContextInitializer ServletContextInitializer[] mergedInitializers = mergeInitializers(initializers); Initializer initializer = new Initializer(mergedInitializers); deployment.addServletContainerInitializer(new ServletContainerInitializerInfo(Initializer.class, - new ImmediateInstanceFactory(initializer), NO_CLASSES)); + new ImmediateInstanceFactory<>(initializer), NO_CLASSES)); } private ClassLoader getServletClassLoader() { diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/AbstractFilterRegistrationBeanTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/AbstractFilterRegistrationBeanTests.java index 12835e9d24e6..140a87806496 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/AbstractFilterRegistrationBeanTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/AbstractFilterRegistrationBeanTests.java @@ -139,8 +139,7 @@ void addServletRegistrationBeanMustNotBeNull() { void setServletRegistrationBeanReplacesValue() throws Exception { given(this.servletContext.addFilter(anyString(), any(Filter.class))).willReturn(this.registration); AbstractFilterRegistrationBean bean = createFilterRegistrationBean(mockServletRegistration("a")); - bean.setServletRegistrationBeans( - new LinkedHashSet>(Collections.singletonList(mockServletRegistration("b")))); + bean.setServletRegistrationBeans(new LinkedHashSet<>(Collections.singletonList(mockServletRegistration("b")))); bean.onStartup(this.servletContext); then(this.registration).should().addMappingForServletNames(EnumSet.of(DispatcherType.REQUEST), false, "b"); } diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-actuator-ui/src/test/java/smoketest/actuator/ui/SampleActuatorUiApplicationTests.java b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-actuator-ui/src/test/java/smoketest/actuator/ui/SampleActuatorUiApplicationTests.java index a5199c4b0ff5..e098c5b3192b 100644 --- a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-actuator-ui/src/test/java/smoketest/actuator/ui/SampleActuatorUiApplicationTests.java +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-actuator-ui/src/test/java/smoketest/actuator/ui/SampleActuatorUiApplicationTests.java @@ -50,7 +50,7 @@ void testHome() { HttpHeaders headers = new HttpHeaders(); headers.setAccept(Arrays.asList(MediaType.TEXT_HTML)); ResponseEntity entity = this.restTemplate.withBasicAuth("user", getPassword()) - .exchange("/", HttpMethod.GET, new HttpEntity(headers), String.class); + .exchange("/", HttpMethod.GET, new HttpEntity<>(headers), String.class); assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(entity.getBody()).contains("Codestin Search App"); } diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-web-secure-jdbc/src/test/java/smoketest/web/secure/jdbc/SampleWebSecureJdbcApplicationTests.java b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-web-secure-jdbc/src/test/java/smoketest/web/secure/jdbc/SampleWebSecureJdbcApplicationTests.java index ee35c052e9b2..5f7871f25e37 100644 --- a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-web-secure-jdbc/src/test/java/smoketest/web/secure/jdbc/SampleWebSecureJdbcApplicationTests.java +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-web-secure-jdbc/src/test/java/smoketest/web/secure/jdbc/SampleWebSecureJdbcApplicationTests.java @@ -55,7 +55,7 @@ class SampleWebSecureJdbcApplicationTests { void testHome() { HttpHeaders headers = new HttpHeaders(); headers.setAccept(Collections.singletonList(MediaType.TEXT_HTML)); - ResponseEntity entity = this.restTemplate.exchange("/", HttpMethod.GET, new HttpEntity(headers), + ResponseEntity entity = this.restTemplate.exchange("/", HttpMethod.GET, new HttpEntity<>(headers), String.class); assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FOUND); assertThat(entity.getHeaders().getLocation().toString()).endsWith(this.port + "/login"); @@ -65,8 +65,8 @@ void testHome() { void testLoginPage() { HttpHeaders headers = new HttpHeaders(); headers.setAccept(Collections.singletonList(MediaType.TEXT_HTML)); - ResponseEntity entity = this.restTemplate.exchange("/login", HttpMethod.GET, - new HttpEntity(headers), String.class); + ResponseEntity entity = this.restTemplate.exchange("/login", HttpMethod.GET, new HttpEntity<>(headers), + String.class); assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(entity.getBody()).contains("Codestin Search App"); } diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-web-secure/src/test/java/smoketest/web/secure/SampleWebSecureApplicationTests.java b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-web-secure/src/test/java/smoketest/web/secure/SampleWebSecureApplicationTests.java index ae6ae5067d50..f2d10b0b47d1 100644 --- a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-web-secure/src/test/java/smoketest/web/secure/SampleWebSecureApplicationTests.java +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-web-secure/src/test/java/smoketest/web/secure/SampleWebSecureApplicationTests.java @@ -62,8 +62,8 @@ class SampleWebSecureApplicationTests { void testHome() { HttpHeaders headers = new HttpHeaders(); headers.setAccept(Collections.singletonList(MediaType.TEXT_HTML)); - ResponseEntity entity = this.restTemplate.exchange("/home", HttpMethod.GET, - new HttpEntity(headers), String.class); + ResponseEntity entity = this.restTemplate.exchange("/home", HttpMethod.GET, new HttpEntity<>(headers), + String.class); assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FOUND); assertThat(entity.getHeaders().getLocation().toString()).endsWith(this.port + "/login"); } @@ -72,8 +72,8 @@ void testHome() { void testLoginPage() { HttpHeaders headers = new HttpHeaders(); headers.setAccept(Collections.singletonList(MediaType.TEXT_HTML)); - ResponseEntity entity = this.restTemplate.exchange("/login", HttpMethod.GET, - new HttpEntity(headers), String.class); + ResponseEntity entity = this.restTemplate.exchange("/login", HttpMethod.GET, new HttpEntity<>(headers), + String.class); assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(entity.getBody()).contains("Codestin Search App"); } From f450b28a7c063a1d006d6fc6569b58c896317cdc Mon Sep 17 00:00:00 2001 From: Yanming Zhou Date: Fri, 22 Nov 2024 17:12:46 +0800 Subject: [PATCH 086/203] Add `redirects(...)` method to `RestTemplateBuilder` Add `redirects(...)` method to `RestTemplateBuilder` to allow redirect customization. This new method is required in 3.4 since the default redirect strategy for some clients has changed and users need a way to restore the old behavior. See gh-43258 --- .../test/web/client/TestRestTemplate.java | 24 ++++++++++++++++++- .../web/client/TestRestTemplateTests.java | 18 ++++++++++++++ .../boot/web/client/RestTemplateBuilder.java | 15 ++++++++++++ .../web/client/RestTemplateBuilderTests.java | 9 +++++++ 4 files changed, 65 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/web/client/TestRestTemplate.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/web/client/TestRestTemplate.java index a8d7cf2e9390..af119e1266af 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/web/client/TestRestTemplate.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/web/client/TestRestTemplate.java @@ -47,6 +47,7 @@ import org.apache.hc.core5.ssl.TrustStrategy; import org.springframework.boot.http.client.ClientHttpRequestFactorySettings; +import org.springframework.boot.http.client.ClientHttpRequestFactorySettings.Redirects; import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.boot.web.client.RootUriTemplateHandler; import org.springframework.core.ParameterizedTypeReference; @@ -92,6 +93,7 @@ * @author Andy Wilkinson * @author Kristine Jetzke * @author Dmytro Nosan + * @author Yanming Zhou * @since 1.4.0 */ public class TestRestTemplate { @@ -946,6 +948,22 @@ public TestRestTemplate withBasicAuth(String username, String password) { return template; } + /** + * Creates a new {@code TestRestTemplate} with the same configuration as this one, + * except that it will use the given {@code redirects} strategies. The request factory + * used is a new instance of the underlying {@link RestTemplate}'s request factory + * type (when possible). + * @param redirects the redirects + * @return the new template + * @since 3.4.1 + */ + public TestRestTemplate withRedirects(Redirects redirects) { + TestRestTemplate template = new TestRestTemplate(this.builder.redirects(redirects), null, null, + this.httpClientOptions); + template.setUriTemplateHandler(getRestTemplate().getUriTemplateHandler()); + return template; + } + @SuppressWarnings({ "rawtypes", "unchecked" }) private RequestEntity createRequestEntityWithRootAppliedUri(RequestEntity requestEntity) { return new RequestEntity(requestEntity.getBody(), requestEntity.getHeaders(), requestEntity.getMethod(), @@ -988,7 +1006,10 @@ public enum HttpClientOption { /** * Enable redirects. + * @deprecated since 3.4.1 for removal in 3.6.0 in favor of + * {@link #withRedirects(Redirects)} */ + @Deprecated(since = "3.4.1", forRemoval = true) ENABLE_REDIRECTS, /** @@ -1032,7 +1053,8 @@ public CustomHttpComponentsClientHttpRequestFactory(HttpClientOption[] httpClien Set options = new HashSet<>(Arrays.asList(httpClientOptions)); this.cookieSpec = (options.contains(HttpClientOption.ENABLE_COOKIES) ? StandardCookieSpec.STRICT : StandardCookieSpec.IGNORE); - this.enableRedirects = options.contains(HttpClientOption.ENABLE_REDIRECTS); + this.enableRedirects = options.contains(HttpClientOption.ENABLE_REDIRECTS) + || settings.redirects() != Redirects.DONT_FOLLOW; boolean ssl = options.contains(HttpClientOption.SSL); if (settings.readTimeout() != null || ssl) { setHttpClient(createHttpClient(settings.readTimeout(), ssl)); diff --git a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/web/client/TestRestTemplateTests.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/web/client/TestRestTemplateTests.java index 8d5ba9c055e2..3363b3dbe7af 100644 --- a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/web/client/TestRestTemplateTests.java +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/web/client/TestRestTemplateTests.java @@ -26,6 +26,7 @@ import org.apache.hc.client5.http.config.RequestConfig; import org.junit.jupiter.api.Test; +import org.springframework.boot.http.client.ClientHttpRequestFactorySettings.Redirects; import org.springframework.boot.test.web.client.TestRestTemplate.CustomHttpComponentsClientHttpRequestFactory; import org.springframework.boot.test.web.client.TestRestTemplate.HttpClientOption; import org.springframework.boot.web.client.RestTemplateBuilder; @@ -66,6 +67,7 @@ * @author Stephane Nicoll * @author Andy Wilkinson * @author Kristine Jetzke + * @author Yanming Zhou */ class TestRestTemplateTests { @@ -129,6 +131,7 @@ void authenticated() { assertBasicAuthorizationCredentials(restTemplate, "user", "password"); } + @SuppressWarnings("deprecation") @Test void options() { TestRestTemplate template = new TestRestTemplate(HttpClientOption.ENABLE_REDIRECTS); @@ -139,6 +142,21 @@ void options() { assertThat(config.isRedirectsEnabled()).isTrue(); } + @Test + void redirects() { + TestRestTemplate template = new TestRestTemplate().withRedirects(Redirects.DONT_FOLLOW); + CustomHttpComponentsClientHttpRequestFactory factory = (CustomHttpComponentsClientHttpRequestFactory) template + .getRestTemplate() + .getRequestFactory(); + RequestConfig config = factory.createRequestConfig(); + assertThat(config.isRedirectsEnabled()).isFalse(); + + template = new TestRestTemplate().withRedirects(Redirects.FOLLOW); + factory = (CustomHttpComponentsClientHttpRequestFactory) template.getRestTemplate().getRequestFactory(); + config = factory.createRequestConfig(); + assertThat(config.isRedirectsEnabled()).isTrue(); + } + @Test void restOperationsAreAvailable() { RestTemplate delegate = mock(RestTemplate.class); diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/RestTemplateBuilder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/RestTemplateBuilder.java index 2f5e35b5abd6..d8f574b506ef 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/RestTemplateBuilder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/RestTemplateBuilder.java @@ -33,6 +33,7 @@ import org.springframework.beans.BeanUtils; import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder; import org.springframework.boot.http.client.ClientHttpRequestFactorySettings; +import org.springframework.boot.http.client.ClientHttpRequestFactorySettings.Redirects; import org.springframework.boot.ssl.SslBundle; import org.springframework.http.client.ClientHttpRequest; import org.springframework.http.client.ClientHttpRequestFactory; @@ -64,6 +65,7 @@ * @author Kevin Strijbos * @author Ilya Lukyanovich * @author Scott Frederick + * @author Yanming Zhou * @since 1.4.0 */ public class RestTemplateBuilder { @@ -501,6 +503,19 @@ public RestTemplateBuilder readTimeout(Duration readTimeout) { this.defaultHeaders, this.customizers, this.requestCustomizers); } + /** + * Sets the redirect strategy on the underlying {@link ClientHttpRequestFactory}. + * @param redirects the redirect strategy + * @return a new builder instance. + * @since 3.4.1 + */ + public RestTemplateBuilder redirects(Redirects redirects) { + return new RestTemplateBuilder(this.requestFactorySettings.withRedirects(redirects), this.detectRequestFactory, + this.rootUri, this.messageConverters, this.interceptors, this.requestFactoryBuilder, + this.uriTemplateHandler, this.errorHandler, this.basicAuthentication, this.defaultHeaders, + this.customizers, this.requestCustomizers); + } + /** * Sets the SSL bundle on the underlying {@link ClientHttpRequestFactory}. * @param sslBundle the SSL bundle diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/RestTemplateBuilderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/RestTemplateBuilderTests.java index 0b2e39a75cab..c62b22b58b7d 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/RestTemplateBuilderTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/RestTemplateBuilderTests.java @@ -32,6 +32,7 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.boot.http.client.ClientHttpRequestFactorySettings; +import org.springframework.boot.http.client.ClientHttpRequestFactorySettings.Redirects; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; @@ -73,6 +74,7 @@ * @author Kevin Strijbos * @author Ilya Lukyanovich * @author Brian Clozel + * @author Yanming Zhou */ @ExtendWith(MockitoExtension.class) class RestTemplateBuilderTests { @@ -486,6 +488,13 @@ void unwrappingDoesNotAffectRequestFactoryThatIsSetOnTheBuiltTemplate() { assertThat(template.getRequestFactory()).isInstanceOf(BufferingClientHttpRequestFactory.class); } + @Test + void configureRedirects() { + assertThat(this.builder.redirects(Redirects.DONT_FOLLOW)).extracting("requestFactorySettings") + .extracting("redirects") + .isSameAs(Redirects.DONT_FOLLOW); + } + private ClientHttpRequest createRequest(RestTemplate template) { return ReflectionTestUtils.invokeMethod(template, "createRequest", URI.create("http://localhost"), HttpMethod.GET); From 8b83afdb681a9e889857dd06c4df557a27e1c042 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 4 Dec 2024 13:33:12 -0800 Subject: [PATCH 087/203] Polish 'Add `redirects(...)` method to `RestTemplateBuilder`' Remove deprecations and new methods in `TestRestTemplate` in favor of passing in a configured `RestTemplateBuilder`. See gh-43258 --- .../test/web/client/TestRestTemplate.java | 19 ------- .../web/client/TestRestTemplateTests.java | 57 ++++++++++++++----- 2 files changed, 43 insertions(+), 33 deletions(-) diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/web/client/TestRestTemplate.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/web/client/TestRestTemplate.java index af119e1266af..f0629aa3dbb2 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/web/client/TestRestTemplate.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/web/client/TestRestTemplate.java @@ -948,22 +948,6 @@ public TestRestTemplate withBasicAuth(String username, String password) { return template; } - /** - * Creates a new {@code TestRestTemplate} with the same configuration as this one, - * except that it will use the given {@code redirects} strategies. The request factory - * used is a new instance of the underlying {@link RestTemplate}'s request factory - * type (when possible). - * @param redirects the redirects - * @return the new template - * @since 3.4.1 - */ - public TestRestTemplate withRedirects(Redirects redirects) { - TestRestTemplate template = new TestRestTemplate(this.builder.redirects(redirects), null, null, - this.httpClientOptions); - template.setUriTemplateHandler(getRestTemplate().getUriTemplateHandler()); - return template; - } - @SuppressWarnings({ "rawtypes", "unchecked" }) private RequestEntity createRequestEntityWithRootAppliedUri(RequestEntity requestEntity) { return new RequestEntity(requestEntity.getBody(), requestEntity.getHeaders(), requestEntity.getMethod(), @@ -1006,10 +990,7 @@ public enum HttpClientOption { /** * Enable redirects. - * @deprecated since 3.4.1 for removal in 3.6.0 in favor of - * {@link #withRedirects(Redirects)} */ - @Deprecated(since = "3.4.1", forRemoval = true) ENABLE_REDIRECTS, /** diff --git a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/web/client/TestRestTemplateTests.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/web/client/TestRestTemplateTests.java index 3363b3dbe7af..1d866608885f 100644 --- a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/web/client/TestRestTemplateTests.java +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/web/client/TestRestTemplateTests.java @@ -20,12 +20,15 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpClient.Redirect; import java.util.Base64; import java.util.stream.Stream; import org.apache.hc.client5.http.config.RequestConfig; import org.junit.jupiter.api.Test; +import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder; import org.springframework.boot.http.client.ClientHttpRequestFactorySettings.Redirects; import org.springframework.boot.test.web.client.TestRestTemplate.CustomHttpComponentsClientHttpRequestFactory; import org.springframework.boot.test.web.client.TestRestTemplate.HttpClientOption; @@ -39,6 +42,7 @@ import org.springframework.http.client.ClientHttpRequest; import org.springframework.http.client.ClientHttpRequestFactory; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.http.client.JdkClientHttpRequestFactory; import org.springframework.http.client.SimpleClientHttpRequestFactory; import org.springframework.mock.env.MockEnvironment; import org.springframework.mock.http.client.MockClientHttpRequest; @@ -131,30 +135,55 @@ void authenticated() { assertBasicAuthorizationCredentials(restTemplate, "user", "password"); } - @SuppressWarnings("deprecation") @Test void options() { - TestRestTemplate template = new TestRestTemplate(HttpClientOption.ENABLE_REDIRECTS); - CustomHttpComponentsClientHttpRequestFactory factory = (CustomHttpComponentsClientHttpRequestFactory) template - .getRestTemplate() - .getRequestFactory(); - RequestConfig config = factory.createRequestConfig(); + RequestConfig config = getRequestConfig( + new TestRestTemplate(HttpClientOption.ENABLE_REDIRECTS, HttpClientOption.ENABLE_COOKIES)); assertThat(config.isRedirectsEnabled()).isTrue(); + assertThat(config.getCookieSpec()).isEqualTo("strict"); } @Test - void redirects() { - TestRestTemplate template = new TestRestTemplate().withRedirects(Redirects.DONT_FOLLOW); + void jdkBuilderCanBeSpecifiedWithSpecificRedirects() { + RestTemplateBuilder builder = new RestTemplateBuilder() + .requestFactoryBuilder(ClientHttpRequestFactoryBuilder.jdk()); + TestRestTemplate templateWithRedirects = new TestRestTemplate(builder.redirects(Redirects.FOLLOW)); + assertThat(getJdkHttpClient(templateWithRedirects).followRedirects()).isEqualTo(Redirect.NORMAL); + TestRestTemplate templateWithoutRedirects = new TestRestTemplate(builder.redirects(Redirects.DONT_FOLLOW)); + assertThat(getJdkHttpClient(templateWithoutRedirects).followRedirects()).isEqualTo(Redirect.NEVER); + } + + @Test + void httpComponentsAreBuildConsideringSettingsInRestTemplateBuilder() { + RestTemplateBuilder builder = new RestTemplateBuilder() + .requestFactoryBuilder(ClientHttpRequestFactoryBuilder.httpComponents()); + assertThat(getRequestConfig((RestTemplateBuilder) null).isRedirectsEnabled()).isTrue(); + assertThat(getRequestConfig(null, HttpClientOption.ENABLE_REDIRECTS).isRedirectsEnabled()).isTrue(); + assertThat(getRequestConfig(builder).isRedirectsEnabled()).isTrue(); + assertThat(getRequestConfig(builder, HttpClientOption.ENABLE_REDIRECTS).isRedirectsEnabled()).isTrue(); + assertThat(getRequestConfig(builder.redirects(Redirects.DONT_FOLLOW)).isRedirectsEnabled()).isFalse(); + assertThat(getRequestConfig(builder.redirects(Redirects.DONT_FOLLOW), HttpClientOption.ENABLE_REDIRECTS) + .isRedirectsEnabled()).isTrue(); + } + + private RequestConfig getRequestConfig(RestTemplateBuilder builder, HttpClientOption... httpClientOptions) { + builder = (builder != null) ? builder : new RestTemplateBuilder(); + TestRestTemplate template = new TestRestTemplate(builder, null, null, httpClientOptions); + return getRequestConfig(template); + } + + private RequestConfig getRequestConfig(TestRestTemplate template) { CustomHttpComponentsClientHttpRequestFactory factory = (CustomHttpComponentsClientHttpRequestFactory) template .getRestTemplate() .getRequestFactory(); - RequestConfig config = factory.createRequestConfig(); - assertThat(config.isRedirectsEnabled()).isFalse(); + return factory.createRequestConfig(); + } - template = new TestRestTemplate().withRedirects(Redirects.FOLLOW); - factory = (CustomHttpComponentsClientHttpRequestFactory) template.getRestTemplate().getRequestFactory(); - config = factory.createRequestConfig(); - assertThat(config.isRedirectsEnabled()).isTrue(); + private HttpClient getJdkHttpClient(TestRestTemplate templateWithRedirects) { + JdkClientHttpRequestFactory requestFactory = (JdkClientHttpRequestFactory) templateWithRedirects + .getRestTemplate() + .getRequestFactory(); + return (HttpClient) ReflectionTestUtils.getField(requestFactory, "httpClient"); } @Test From dd14158ad7fd4bae5263aa3229b9239187d10763 Mon Sep 17 00:00:00 2001 From: Yanming Zhou Date: Wed, 27 Nov 2024 16:36:26 +0800 Subject: [PATCH 088/203] Document how to use structured logging with custom log configuration See gh-43301 --- .../reference/pages/features/logging.adoc | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/logging.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/logging.adoc index bf2d7b5cca91..7fa0b1d1d398 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/logging.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/logging.adoc @@ -450,6 +450,34 @@ Spring Boot supports structured logging and has support for the following JSON f To enable structured logging, set the property configprop:logging.structured.format.console[] (for console output) or configprop:logging.structured.format.file[] (for file output) to the id of the format you want to use. +If you are using xref:#features.logging.custom-log-configuration[Custom Log Configuration], update your configuration to respect `CONSOLE_LOG_STRUCTURED_FORMAT` and `FILE_LOG_STRUCTURED_FORMAT` system properties. +Take `CONSOLE_LOG_STRUCTURED_FORMAT` for example: +[tabs] +====== +Logback:: ++ +[source,xml] +---- + + + ${CONSOLE_LOG_STRUCTURED_FORMAT} + ${CONSOLE_LOG_CHARSET} + +---- +Log4j2:: ++ +[source,xml] +---- + + +---- +====== +You can refer to default configurations in `spring-boot.jar` for fine-grained control: + +* {code-spring-boot}/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/logback/structured-console-appender.xml[Logback Structured Console Appender] +* {code-spring-boot}/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/logback/structured-file-appender.xml[Logback Structured File Appender] +* {code-spring-boot}/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/log4j2/log4j2.xml[Log4j2 Console Appender] +* {code-spring-boot}/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/log4j2/log4j2-file.xml[Log4j2 Console and File Appender] [[features.logging.structured.ecs]] From 2ff6dea5caf766cadf2696dc1e5b33b15982cf8d Mon Sep 17 00:00:00 2001 From: Moritz Halbritter Date: Thu, 5 Dec 2024 10:13:08 +0100 Subject: [PATCH 089/203] Polish "Document how to use structured logging with custom log configuration" See gh-43301 --- .../modules/reference/pages/features/logging.adoc | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/logging.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/logging.adoc index 7fa0b1d1d398..4af1cb203004 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/logging.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/logging.adoc @@ -464,6 +464,11 @@ Logback:: ${CONSOLE_LOG_CHARSET} ---- ++ +You can also refer to the default configurations included in Spring Boot: ++ +* {code-spring-boot}/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/logback/structured-console-appender.xml[Logback Structured Console Appender] +* {code-spring-boot}/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/logback/structured-file-appender.xml[Logback Structured File Appender] Log4j2:: + [source,xml] @@ -471,13 +476,12 @@ Log4j2:: ---- -====== -You can refer to default configurations in `spring-boot.jar` for fine-grained control: - -* {code-spring-boot}/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/logback/structured-console-appender.xml[Logback Structured Console Appender] -* {code-spring-boot}/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/logback/structured-file-appender.xml[Logback Structured File Appender] ++ +You can also refer to the default configurations included in Spring Boot: ++ * {code-spring-boot}/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/log4j2/log4j2.xml[Log4j2 Console Appender] * {code-spring-boot}/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/log4j2/log4j2-file.xml[Log4j2 Console and File Appender] +====== [[features.logging.structured.ecs]] From dbe7ecd168fdd52488599bb162f1bd1ce4ce7375 Mon Sep 17 00:00:00 2001 From: Tran Ngoc Nhan Date: Thu, 5 Dec 2024 01:11:00 +0700 Subject: [PATCH 090/203] Fix Junit javadoc links See gh-43383 --- spring-boot-project/spring-boot-dependencies/build.gradle | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 30c36a404f24..653705505196 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -1072,7 +1072,8 @@ bom { } links { site("https://junit.org/junit5") - javadoc("https://junit.org/junit5/docs/{version}/api", "org.junit.jupiter.api", "org.junit.platform") + javadoc("junit-platform-engine", version -> "https://junit.org/junit5/docs/%s/api/org.junit.platform.engine".formatted(version), "org.junit.platform") + javadoc("junit-jupiter-api", version -> "https://junit.org/junit5/docs/%s/api/org.junit.jupiter.api".formatted(version), "org.junit.jupiter.api") docs("https://junit.org/junit5/docs/{version}/user-guide") releaseNotes("https://junit.org/junit5/docs/{version}/release-notes") } From fe1f9b30022994ed9456688887a3cacda68693b1 Mon Sep 17 00:00:00 2001 From: Leonid Bogdanov Date: Thu, 5 Dec 2024 13:49:44 +1100 Subject: [PATCH 091/203] Only set imagePlatform if it has text See gh-43424 --- .../src/main/java/org/springframework/boot/maven/Image.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Image.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Image.java index a72373c06b7f..e90d901fc474 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Image.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Image.java @@ -257,7 +257,7 @@ private BuildRequest customize(BuildRequest request) { if (StringUtils.hasText(this.runImage)) { request = request.withRunImage(ImageReference.of(this.runImage)); } - if (this.env != null && !this.env.isEmpty()) { + if (!CollectionUtils.isEmpty(this.env)) { request = request.withEnv(this.env); } if (this.cleanCache != null) { @@ -295,10 +295,10 @@ private BuildRequest customize(BuildRequest request) { if (StringUtils.hasText(this.applicationDirectory)) { request = request.withApplicationDirectory(this.applicationDirectory); } - if (this.securityOptions != null) { + if (!CollectionUtils.isEmpty(this.securityOptions)) { request = request.withSecurityOptions(this.securityOptions); } - if (this.imagePlatform != null) { + if (StringUtils.hasText(this.imagePlatform)) { request = request.withImagePlatform(this.imagePlatform); } return request; From 4dca6ee5d3fa188a56d74c71787cd86226b75652 Mon Sep 17 00:00:00 2001 From: Moritz Halbritter Date: Thu, 5 Dec 2024 11:03:14 +0100 Subject: [PATCH 092/203] Polish "Only set imagePlatform if it has text" See gh-43424 --- .../main/java/org/springframework/boot/maven/Image.java | 2 +- .../java/org/springframework/boot/maven/ImageTests.java | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Image.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Image.java index e90d901fc474..a681b031906f 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Image.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Image.java @@ -295,7 +295,7 @@ private BuildRequest customize(BuildRequest request) { if (StringUtils.hasText(this.applicationDirectory)) { request = request.withApplicationDirectory(this.applicationDirectory); } - if (!CollectionUtils.isEmpty(this.securityOptions)) { + if (this.securityOptions != null) { request = request.withSecurityOptions(this.securityOptions); } if (StringUtils.hasText(this.imagePlatform)) { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/ImageTests.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/ImageTests.java index 053ec87bd8eb..12b376054365 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/ImageTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/ImageTests.java @@ -49,6 +49,7 @@ * @author Scott Frederick * @author Jeroen Meijer * @author Rafael Ceccone + * @author Moritz Halbritter */ class ImageTests { @@ -290,6 +291,14 @@ void getBuildRequestWhenHasImagePlatformUsesImagePlatform() { assertThat(request.getImagePlatform()).isEqualTo(ImagePlatform.of("linux/arm64")); } + @Test + void getBuildRequestWhenImagePlatformIsEmptyDoesntSetImagePlatform() { + Image image = new Image(); + image.imagePlatform = ""; + BuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent()); + assertThat(request.getImagePlatform()).isNull(); + } + private Artifact createArtifact() { return new DefaultArtifact("com.example", "my-app", VersionRange.createFromVersion("0.0.1-SNAPSHOT"), "compile", "jar", null, new DefaultArtifactHandler()); From 8ca8ab14f66fde79a8f67f56c4ed291ec613b747 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Thu, 5 Dec 2024 18:01:09 -0800 Subject: [PATCH 093/203] Add `withRequestFactorySettings` method and restore previous defaults Update `TestRestTemplate` with a `withRequestFactorySettings` method that can be used to change defaults such as `Redirects`. This commit also restores the previous redirect defaults for HTTP components where redirects would only be followed when the `HttpClientOption.ENABLE_REDIRECTS` was specified. Closes gh-43258 --- .../test/web/client/TestRestTemplate.java | 62 ++++++++++++++----- .../web/client/TestRestTemplateTests.java | 24 ++++++- 2 files changed, 67 insertions(+), 19 deletions(-) diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/web/client/TestRestTemplate.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/web/client/TestRestTemplate.java index f0629aa3dbb2..46c9067f8df3 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/web/client/TestRestTemplate.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/web/client/TestRestTemplate.java @@ -22,8 +22,6 @@ import java.security.NoSuchAlgorithmException; import java.security.cert.X509Certificate; import java.time.Duration; -import java.util.Arrays; -import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -60,6 +58,7 @@ import org.springframework.http.client.ClientHttpRequestFactory; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; import org.springframework.web.client.NoOpResponseErrorHandler; import org.springframework.web.client.RequestCallback; import org.springframework.web.client.ResponseExtractor; @@ -100,8 +99,6 @@ public class TestRestTemplate { private final RestTemplateBuilder builder; - private final HttpClientOption[] httpClientOptions; - private final RestTemplate restTemplate; /** @@ -142,12 +139,26 @@ public TestRestTemplate(String username, String password, HttpClientOption... ht */ public TestRestTemplate(RestTemplateBuilder builder, String username, String password, HttpClientOption... httpClientOptions) { - Assert.notNull(builder, "Builder must not be null"); + this(createInitialBuilder(builder, username, password, httpClientOptions), null); + } + + private TestRestTemplate(RestTemplateBuilder builder, UriTemplateHandler uriTemplateHandler) { this.builder = builder; - this.httpClientOptions = httpClientOptions; + this.restTemplate = builder.build(); + if (uriTemplateHandler != null) { + this.restTemplate.setUriTemplateHandler(uriTemplateHandler); + } + this.restTemplate.setErrorHandler(new NoOpResponseErrorHandler()); + } + + private static RestTemplateBuilder createInitialBuilder(RestTemplateBuilder builder, String username, + String password, HttpClientOption... httpClientOptions) { + Assert.notNull(builder, "Builder must not be null"); if (httpClientOptions != null) { ClientHttpRequestFactory requestFactory = builder.buildRequestFactory(); if (requestFactory instanceof HttpComponentsClientHttpRequestFactory) { + builder = builder.redirects(HttpClientOption.ENABLE_REDIRECTS.isPresent(httpClientOptions) + ? Redirects.FOLLOW : Redirects.DONT_FOLLOW); builder = builder.requestFactoryBuilder( (settings) -> new CustomHttpComponentsClientHttpRequestFactory(httpClientOptions, settings)); } @@ -155,8 +166,7 @@ public TestRestTemplate(RestTemplateBuilder builder, String username, String pas if (username != null || password != null) { builder = builder.basicAuthentication(username, password); } - this.restTemplate = builder.build(); - this.restTemplate.setErrorHandler(new NoOpResponseErrorHandler()); + return builder; } /** @@ -943,9 +953,25 @@ public RestTemplate getRestTemplate() { * @since 1.4.1 */ public TestRestTemplate withBasicAuth(String username, String password) { - TestRestTemplate template = new TestRestTemplate(this.builder, username, password, this.httpClientOptions); - template.setUriTemplateHandler(getRestTemplate().getUriTemplateHandler()); - return template; + if (username == null && password == null) { + return this; + } + return new TestRestTemplate(this.builder.basicAuthentication(username, password), + this.restTemplate.getUriTemplateHandler()); + } + + /** + * Creates a new {@code TestRestTemplate} with the same configuration as this one, + * except that it will apply the given {@link ClientHttpRequestFactorySettings}. The + * request factory used is a new instance of the underlying {@link RestTemplate}'s + * request factory type (when possible). + * @param requestFactorySettings the new request factory settings + * @return the new template + * @since 3.4.1 + */ + public TestRestTemplate withRequestFactorySettings(ClientHttpRequestFactorySettings requestFactorySettings) { + return new TestRestTemplate(this.builder.requestFactorySettings(requestFactorySettings), + this.restTemplate.getUriTemplateHandler()); } @SuppressWarnings({ "rawtypes", "unchecked" }) @@ -996,7 +1022,11 @@ public enum HttpClientOption { /** * Use a {@link TlsSocketStrategy} that trusts self-signed certificates. */ - SSL + SSL; + + boolean isPresent(HttpClientOption[] options) { + return ObjectUtils.containsElement(options, this); + } } @@ -1031,12 +1061,10 @@ public CustomHttpComponentsClientHttpRequestFactory(HttpClientOption[] httpClien */ public CustomHttpComponentsClientHttpRequestFactory(HttpClientOption[] httpClientOptions, ClientHttpRequestFactorySettings settings) { - Set options = new HashSet<>(Arrays.asList(httpClientOptions)); - this.cookieSpec = (options.contains(HttpClientOption.ENABLE_COOKIES) ? StandardCookieSpec.STRICT + this.cookieSpec = (HttpClientOption.ENABLE_COOKIES.isPresent(httpClientOptions) ? StandardCookieSpec.STRICT : StandardCookieSpec.IGNORE); - this.enableRedirects = options.contains(HttpClientOption.ENABLE_REDIRECTS) - || settings.redirects() != Redirects.DONT_FOLLOW; - boolean ssl = options.contains(HttpClientOption.SSL); + this.enableRedirects = settings.redirects() != Redirects.DONT_FOLLOW; + boolean ssl = HttpClientOption.SSL.isPresent(httpClientOptions); if (settings.readTimeout() != null || ssl) { setHttpClient(createHttpClient(settings.readTimeout(), ssl)); } diff --git a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/web/client/TestRestTemplateTests.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/web/client/TestRestTemplateTests.java index 1d866608885f..dc99a59174a3 100644 --- a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/web/client/TestRestTemplateTests.java +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/web/client/TestRestTemplateTests.java @@ -29,6 +29,7 @@ import org.junit.jupiter.api.Test; import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder; +import org.springframework.boot.http.client.ClientHttpRequestFactorySettings; import org.springframework.boot.http.client.ClientHttpRequestFactorySettings.Redirects; import org.springframework.boot.test.web.client.TestRestTemplate.CustomHttpComponentsClientHttpRequestFactory; import org.springframework.boot.test.web.client.TestRestTemplate.HttpClientOption; @@ -157,15 +158,34 @@ void jdkBuilderCanBeSpecifiedWithSpecificRedirects() { void httpComponentsAreBuildConsideringSettingsInRestTemplateBuilder() { RestTemplateBuilder builder = new RestTemplateBuilder() .requestFactoryBuilder(ClientHttpRequestFactoryBuilder.httpComponents()); - assertThat(getRequestConfig((RestTemplateBuilder) null).isRedirectsEnabled()).isTrue(); + assertThat(getRequestConfig((RestTemplateBuilder) null).isRedirectsEnabled()).isFalse(); assertThat(getRequestConfig(null, HttpClientOption.ENABLE_REDIRECTS).isRedirectsEnabled()).isTrue(); - assertThat(getRequestConfig(builder).isRedirectsEnabled()).isTrue(); + assertThat(getRequestConfig(builder).isRedirectsEnabled()).isFalse(); assertThat(getRequestConfig(builder, HttpClientOption.ENABLE_REDIRECTS).isRedirectsEnabled()).isTrue(); assertThat(getRequestConfig(builder.redirects(Redirects.DONT_FOLLOW)).isRedirectsEnabled()).isFalse(); assertThat(getRequestConfig(builder.redirects(Redirects.DONT_FOLLOW), HttpClientOption.ENABLE_REDIRECTS) .isRedirectsEnabled()).isTrue(); } + @Test + void withSettingsUpdatesRedirectsForHttpComponents() { + TestRestTemplate template = new TestRestTemplate(); + assertThat(getRequestConfig(template).isRedirectsEnabled()).isFalse(); + assertThat(getRequestConfig(template + .withRequestFactorySettings(ClientHttpRequestFactorySettings.defaults().withRedirects(Redirects.FOLLOW))) + .isRedirectsEnabled()).isTrue(); + } + + @Test + void withSettingsUpdatesRedirectsForJdk() { + TestRestTemplate template = new TestRestTemplate( + new RestTemplateBuilder().requestFactoryBuilder(ClientHttpRequestFactoryBuilder.jdk())); + assertThat(getJdkHttpClient(template).followRedirects()).isEqualTo(Redirect.NORMAL); + assertThat(getJdkHttpClient(template.withRequestFactorySettings( + ClientHttpRequestFactorySettings.defaults().withRedirects(Redirects.DONT_FOLLOW))) + .followRedirects()).isEqualTo(Redirect.NEVER); + } + private RequestConfig getRequestConfig(RestTemplateBuilder builder, HttpClientOption... httpClientOptions) { builder = (builder != null) ? builder : new RestTemplateBuilder(); TestRestTemplate template = new TestRestTemplate(builder, null, null, httpClientOptions); From 86b0c768e72a5c2d4c2488718434e5d2f1bcfb3f Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Thu, 5 Dec 2024 14:44:38 -0800 Subject: [PATCH 094/203] Fix annotation matching when using scoped proxies Update `OnBeanCondition` to check `isAutowireCandidate` on the original bean of scoped proxy targets. Fixes gh-43423 --- .../condition/OnBeanCondition.java | 47 ++++++++++++++----- .../ConditionalOnMissingBeanTests.java | 47 +++++++++++++++++++ 2 files changed, 81 insertions(+), 13 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnBeanCondition.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnBeanCondition.java index 631e011e9423..25ef759f726f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnBeanCondition.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnBeanCondition.java @@ -202,16 +202,10 @@ private ConditionOutcome evaluateConditionalOnMissingBean(Spec spec) { + ConfigurableListableBeanFactory beanFactory = getSearchBeanFactory(spec); ClassLoader classLoader = spec.getContext().getClassLoader(); - ConfigurableListableBeanFactory beanFactory = spec.getContext().getBeanFactory(); boolean considerHierarchy = spec.getStrategy() != SearchStrategy.CURRENT; Set> parameterizedContainers = spec.getParameterizedContainers(); - if (spec.getStrategy() == SearchStrategy.ANCESTORS) { - BeanFactory parent = beanFactory.getParentBeanFactory(); - Assert.isInstanceOf(ConfigurableListableBeanFactory.class, parent, - "Unable to use SearchStrategy.ANCESTORS"); - beanFactory = (ConfigurableListableBeanFactory) parent; - } MatchResult result = new MatchResult(); Set beansIgnoredByType = getNamesOfBeansIgnoredByType(classLoader, beanFactory, considerHierarchy, spec.getIgnoredTypes(), parameterizedContainers); @@ -219,8 +213,8 @@ protected final MatchResult getMatchingBeans(Spec spec) { Map typeMatchedDefinitions = getBeanDefinitionsForType(classLoader, considerHierarchy, beanFactory, type, parameterizedContainers); Set typeMatchedNames = matchedNamesFrom(typeMatchedDefinitions, - (name, definition) -> isCandidate(name, definition, beansIgnoredByType) - && !ScopedProxyUtils.isScopedTarget(name)); + (name, definition) -> !ScopedProxyUtils.isScopedTarget(name) + && isCandidate(beanFactory, name, definition, beansIgnoredByType)); if (typeMatchedNames.isEmpty()) { result.recordUnmatchedType(type); } @@ -232,7 +226,7 @@ protected final MatchResult getMatchingBeans(Spec spec) { Map annotationMatchedDefinitions = getBeanDefinitionsForAnnotation(classLoader, beanFactory, annotation, considerHierarchy); Set annotationMatchedNames = matchedNamesFrom(annotationMatchedDefinitions, - (name, definition) -> isCandidate(name, definition, beansIgnoredByType)); + (name, definition) -> isCandidate(beanFactory, name, definition, beansIgnoredByType)); if (annotationMatchedNames.isEmpty()) { result.recordUnmatchedAnnotation(annotation); } @@ -252,6 +246,17 @@ protected final MatchResult getMatchingBeans(Spec spec) { return result; } + private ConfigurableListableBeanFactory getSearchBeanFactory(Spec spec) { + ConfigurableListableBeanFactory beanFactory = spec.getContext().getBeanFactory(); + if (spec.getStrategy() == SearchStrategy.ANCESTORS) { + BeanFactory parent = beanFactory.getParentBeanFactory(); + Assert.isInstanceOf(ConfigurableListableBeanFactory.class, parent, + "Unable to use SearchStrategy.ANCESTORS"); + beanFactory = (ConfigurableListableBeanFactory) parent; + } + return beanFactory; + } + private Set matchedNamesFrom(Map namedDefinitions, BiPredicate filter) { Set matchedNames = new LinkedHashSet<>(namedDefinitions.size()); @@ -263,9 +268,25 @@ private Set matchedNamesFrom(Map namedDefinition return matchedNames; } - private boolean isCandidate(String name, BeanDefinition definition, Set ignoredBeans) { - return (!ignoredBeans.contains(name)) - && (definition == null || (definition.isAutowireCandidate() && isDefaultCandidate(definition))); + private boolean isCandidate(ConfigurableListableBeanFactory beanFactory, String name, BeanDefinition definition, + Set ignoredBeans) { + return (!ignoredBeans.contains(name)) && (definition == null + || isAutowireCandidate(beanFactory, name, definition) && isDefaultCandidate(definition)); + } + + private boolean isAutowireCandidate(ConfigurableListableBeanFactory beanFactory, String name, + BeanDefinition definition) { + return definition.isAutowireCandidate() || isScopeTargetAutowireCandidate(beanFactory, name); + } + + private boolean isScopeTargetAutowireCandidate(ConfigurableListableBeanFactory beanFactory, String name) { + try { + return ScopedProxyUtils.isScopedTarget(name) + && beanFactory.getBeanDefinition(ScopedProxyUtils.getOriginalBeanName(name)).isAutowireCandidate(); + } + catch (NoSuchBeanDefinitionException ex) { + return false; + } } private boolean isDefaultCandidate(BeanDefinition definition) { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnMissingBeanTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnMissingBeanTests.java index 61fadfec7e1e..d27d4af67edf 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnMissingBeanTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnMissingBeanTests.java @@ -45,6 +45,9 @@ import org.springframework.context.annotation.Import; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.context.annotation.ImportResource; +import org.springframework.context.annotation.Scope; +import org.springframework.context.annotation.ScopedProxyMode; +import org.springframework.context.support.SimpleThreadScope; import org.springframework.core.type.AnnotationMetadata; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -124,6 +127,16 @@ void testAnnotationOnMissingBeanCondition() { }); } + @Test + void testAnnotationOnMissingBeanConditionWithScopedProxy() { + this.contextRunner.withInitializer(this::registerScope) + .withUserConfiguration(ScopedExampleBeanConfiguration.class, OnAnnotationConfiguration.class) + .run((context) -> { + assertThat(context).doesNotHaveBean("bar"); + assertThat(context.getBean(ScopedExampleBean.class)).hasToString("test"); + }); + } + @Test void testAnnotationOnMissingBeanConditionWithEagerFactoryBean() { // Rigorous test for SPR-11069 @@ -407,6 +420,10 @@ private Consumer exampleBeanRequirement(String.. }; } + private void registerScope(ConfigurableApplicationContext applicationContext) { + applicationContext.getBeanFactory().registerScope("test", new TestScope()); + } + @Configuration(proxyBeanMethods = false) static class OnBeanInAncestorsConfiguration { @@ -665,6 +682,17 @@ String foo() { } + @Configuration(proxyBeanMethods = false) + @TestAnnotation + static class ScopedFooConfiguration { + + @Bean + String foo() { + return "foo"; + } + + } + @Configuration(proxyBeanMethods = false) static class NotAutowireCandidateConfig { @@ -717,6 +745,12 @@ ExampleBean exampleBean() { } + @Configuration(proxyBeanMethods = false) + @Import(ScopedExampleBean.class) + static class ScopedExampleBeanConfiguration { + + } + @Configuration(proxyBeanMethods = false) static class UnrelatedExampleBeanConfiguration { @@ -893,6 +927,15 @@ public String toString() { } + @Scope(scopeName = "test", proxyMode = ScopedProxyMode.TARGET_CLASS) + static class ScopedExampleBean extends ExampleBean { + + ScopedExampleBean() { + super("test"); + } + + } + static class CustomExampleBean extends ExampleBean { CustomExampleBean() { @@ -931,4 +974,8 @@ public String toString() { } + static class TestScope extends SimpleThreadScope { + + } + } From f21402d4c37d1326c37859bbb8dab3e44d8232c1 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Fri, 6 Dec 2024 17:15:10 -0800 Subject: [PATCH 095/203] Consistently return non-zero exit codes for jarmode failures Update jar mode launchers to catch all exceptions and return a non-zero exit code. This refinement also allows us to consolidate the existing error reporting logic to a central locations. Modes that wish to report a simple error rather than a full stacktrace can throw the newly introduced `JarModeErrorException`. Fixes gh-43435 --- .../boot/jarmode/tools/ExtractCommand.java | 27 +++----------- .../boot/jarmode/tools/Layers.java | 13 ++----- .../boot/jarmode/tools/ListLayersCommand.java | 16 ++------- .../jarmode/tools/ExtractCommandTests.java | 25 +++++++------ .../tools/ExtractLayersCommandTests.java | 7 ++-- .../jarmode/tools/ListLayersCommandTests.java | 9 +++-- ...ommand-printErrorIfLayersAreNotEnabled.txt | 2 -- .../list-layers-output-layers-disabled.txt | 2 -- .../boot/loader/jarmode/JarMode.java | 5 +-- .../loader/jarmode/JarModeErrorException.java | 36 +++++++++++++++++++ .../boot/loader/jarmode/JarModeLauncher.java | 35 +++++++++++++++--- .../boot/loader/jarmode/TestJarMode.java | 8 ++++- .../loader/jarmode/LauncherJarModeTests.java | 20 +++++++++++ .../boot/loader/jarmode/JarMode.java | 5 +-- .../loader/jarmode/JarModeErrorException.java | 36 +++++++++++++++++++ .../boot/loader/launch/JarModeRunner.java | 36 ++++++++++++++++--- .../boot/loader/jarmode/TestJarMode.java | 8 ++++- .../boot/loader/launch/LauncherTests.java | 20 +++++++++++ 18 files changed, 230 insertions(+), 80 deletions(-) delete mode 100644 spring-boot-project/spring-boot-tools/spring-boot-jarmode-tools/src/test/resources/org/springframework/boot/jarmode/tools/ExtractCommand-printErrorIfLayersAreNotEnabled.txt delete mode 100644 spring-boot-project/spring-boot-tools/spring-boot-jarmode-tools/src/test/resources/org/springframework/boot/jarmode/tools/list-layers-output-layers-disabled.txt create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-loader-classic/src/main/java/org/springframework/boot/loader/jarmode/JarModeErrorException.java create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jarmode/JarModeErrorException.java diff --git a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-tools/src/main/java/org/springframework/boot/jarmode/tools/ExtractCommand.java b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-tools/src/main/java/org/springframework/boot/jarmode/tools/ExtractCommand.java index 200080138bd3..c1faf1450a8f 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-tools/src/main/java/org/springframework/boot/jarmode/tools/ExtractCommand.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-tools/src/main/java/org/springframework/boot/jarmode/tools/ExtractCommand.java @@ -43,7 +43,7 @@ import org.springframework.boot.jarmode.tools.JarStructure.Entry; import org.springframework.boot.jarmode.tools.JarStructure.Entry.Type; -import org.springframework.boot.jarmode.tools.Layers.LayersNotEnabledException; +import org.springframework.boot.loader.jarmode.JarModeErrorException; import org.springframework.util.Assert; import org.springframework.util.StreamUtils; import org.springframework.util.StringUtils; @@ -118,12 +118,6 @@ void run(PrintStream out, Map options, List parameters) catch (IOException ex) { throw new UncheckedIOException(ex); } - catch (LayersNotEnabledException ex) { - printError(out, "Layers are not enabled"); - } - catch (AbortException ex) { - printError(out, ex.getMessage()); - } } private static void checkDirectoryIsEmpty(Map options, File destination) { @@ -134,11 +128,11 @@ private static void checkDirectoryIsEmpty(Map options, File dest return; } if (!destination.isDirectory()) { - throw new AbortException(destination.getAbsoluteFile() + " already exists and is not a directory"); + throw new JarModeErrorException(destination.getAbsoluteFile() + " already exists and is not a directory"); } File[] files = destination.listFiles(); if (files != null && files.length > 0) { - throw new AbortException(destination.getAbsoluteFile() + " already exists and is not empty"); + throw new JarModeErrorException(destination.getAbsoluteFile() + " already exists and is not empty"); } } @@ -147,18 +141,13 @@ private void checkJarCompatibility() throws IOException { try (ZipInputStream stream = new ZipInputStream(new FileInputStream(file))) { ZipEntry entry = stream.getNextEntry(); if (entry == null) { - throw new AbortException( + throw new JarModeErrorException( "File '%s' is not compatible; ensure jar file is valid and launch script is not enabled" .formatted(file)); } } } - private void printError(PrintStream out, String message) { - out.println("Error: " + message); - out.println(); - } - private void extractLibraries(FileResolver fileResolver, JarStructure jarStructure, Map options) throws IOException { String librariesDirectory = getLibrariesDirectory(options); @@ -494,12 +483,4 @@ private boolean shouldExtractLayer(String layer) { } - private static final class AbortException extends RuntimeException { - - AbortException(String message) { - super(message); - } - - } - } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-tools/src/main/java/org/springframework/boot/jarmode/tools/Layers.java b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-tools/src/main/java/org/springframework/boot/jarmode/tools/Layers.java index 05eb07ebdc90..89d2f67c4793 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-tools/src/main/java/org/springframework/boot/jarmode/tools/Layers.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-tools/src/main/java/org/springframework/boot/jarmode/tools/Layers.java @@ -19,6 +19,8 @@ import java.util.Iterator; import java.util.zip.ZipEntry; +import org.springframework.boot.loader.jarmode.JarModeErrorException; + /** * Provides information about the jar layers. * @@ -62,22 +64,13 @@ default String getLayer(ZipEntry entry) { * Return a {@link Layers} instance for the currently running application. * @param context the command context * @return a new layers instance - * @throws LayersNotEnabledException if layers are not enabled */ static Layers get(Context context) { IndexedLayers indexedLayers = IndexedLayers.get(context); if (indexedLayers == null) { - throw new LayersNotEnabledException(); + throw new JarModeErrorException("Layers are not enabled"); } return indexedLayers; } - final class LayersNotEnabledException extends RuntimeException { - - LayersNotEnabledException() { - super("Layers not enabled: Failed to load layer index file"); - } - - } - } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-tools/src/main/java/org/springframework/boot/jarmode/tools/ListLayersCommand.java b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-tools/src/main/java/org/springframework/boot/jarmode/tools/ListLayersCommand.java index a2b122ec21ee..8561cfb2ce38 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-tools/src/main/java/org/springframework/boot/jarmode/tools/ListLayersCommand.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-tools/src/main/java/org/springframework/boot/jarmode/tools/ListLayersCommand.java @@ -20,8 +20,6 @@ import java.util.List; import java.util.Map; -import org.springframework.boot.jarmode.tools.Layers.LayersNotEnabledException; - /** * The {@code 'list-layers'} tools command. * @@ -38,22 +36,12 @@ class ListLayersCommand extends Command { @Override void run(PrintStream out, Map options, List parameters) { - try { - Layers layers = Layers.get(this.context); - printLayers(out, layers); - } - catch (LayersNotEnabledException ex) { - printError(out, "Layers are not enabled"); - } + Layers layers = Layers.get(this.context); + printLayers(out, layers); } void printLayers(PrintStream out, Layers layers) { layers.forEach(out::println); } - private void printError(PrintStream out, String message) { - out.println("Error: " + message); - out.println(); - } - } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-tools/src/test/java/org/springframework/boot/jarmode/tools/ExtractCommandTests.java b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-tools/src/test/java/org/springframework/boot/jarmode/tools/ExtractCommandTests.java index 0212d749c1ec..b462536fa14b 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-tools/src/test/java/org/springframework/boot/jarmode/tools/ExtractCommandTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-tools/src/test/java/org/springframework/boot/jarmode/tools/ExtractCommandTests.java @@ -32,7 +32,10 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.springframework.boot.loader.jarmode.JarModeErrorException; + import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatIllegalStateException; /** @@ -172,8 +175,8 @@ void failsOnIncompatibleJar() throws IOException { try (FileWriter writer = new FileWriter(file)) { writer.write("text"); } - TestPrintStream out = run(file); - assertThat(out).contains("is not compatible; ensure jar file is valid and launch script is not enabled"); + assertThatExceptionOfType(JarModeErrorException.class).isThrownBy(() -> run(file)) + .withMessageContaining("is not compatible; ensure jar file is valid and launch script is not enabled"); } @Test @@ -181,8 +184,9 @@ void shouldFailIfDirectoryIsNotEmpty() throws IOException { File destination = file("out"); Files.createDirectories(destination.toPath()); Files.createFile(new File(destination, "file.txt").toPath()); - TestPrintStream out = run(ExtractCommandTests.this.archive, "--destination", destination.getAbsolutePath()); - assertThat(out).contains("already exists and is not empty"); + assertThatExceptionOfType(JarModeErrorException.class) + .isThrownBy(() -> run(ExtractCommandTests.this.archive, "--destination", destination.getAbsolutePath())) + .withMessageContaining("already exists and is not empty"); } @Test @@ -266,10 +270,10 @@ void extractsOnlySelectedLayers() throws IOException { } @Test - void printErrorIfLayersAreNotEnabled() throws IOException { + void failsIfLayersAreNotEnabled() throws IOException { File archive = createArchive(); - TestPrintStream out = run(archive, "--layers"); - assertThat(out).hasSameContentAsResource("ExtractCommand-printErrorIfLayersAreNotEnabled.txt"); + assertThatExceptionOfType(JarModeErrorException.class).isThrownBy(() -> run(archive, "--layers")) + .withMessage("Layers are not enabled"); } } @@ -318,10 +322,11 @@ void extract() throws IOException { } @Test - void printErrorIfLayersAreNotEnabled() throws IOException { + void failsIfLayersAreNotEnabled() throws IOException { File archive = createArchive(); - TestPrintStream out = run(archive, "--launcher", "--layers"); - assertThat(out).hasSameContentAsResource("ExtractCommand-printErrorIfLayersAreNotEnabled.txt"); + assertThatExceptionOfType(JarModeErrorException.class) + .isThrownBy(() -> run(archive, "--launcher", "--layers")) + .withMessage("Layers are not enabled"); } @Test diff --git a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-tools/src/test/java/org/springframework/boot/jarmode/tools/ExtractLayersCommandTests.java b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-tools/src/test/java/org/springframework/boot/jarmode/tools/ExtractLayersCommandTests.java index d3baba1630b2..4d3df2e97ca3 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-tools/src/test/java/org/springframework/boot/jarmode/tools/ExtractLayersCommandTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-tools/src/test/java/org/springframework/boot/jarmode/tools/ExtractLayersCommandTests.java @@ -42,10 +42,12 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.boot.loader.jarmode.JarModeErrorException; import org.springframework.core.io.ClassPathResource; import org.springframework.util.FileCopyUtils; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatIllegalStateException; import static org.mockito.BDDMockito.given; @@ -146,8 +148,9 @@ void runWithJarFileContainingNoEntriesFails() throws IOException { } given(this.context.getArchiveFile()).willReturn(file); try (TestPrintStream out = new TestPrintStream(this)) { - this.command.run(out, Collections.emptyMap(), Collections.emptyList()); - assertThat(out).contains("is not compatible"); + assertThatExceptionOfType(JarModeErrorException.class) + .isThrownBy(() -> this.command.run(out, Collections.emptyMap(), Collections.emptyList())) + .withMessageContaining("is not compatible"); } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-tools/src/test/java/org/springframework/boot/jarmode/tools/ListLayersCommandTests.java b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-tools/src/test/java/org/springframework/boot/jarmode/tools/ListLayersCommandTests.java index 676a105617c8..ed014b1f3371 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-tools/src/test/java/org/springframework/boot/jarmode/tools/ListLayersCommandTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-tools/src/test/java/org/springframework/boot/jarmode/tools/ListLayersCommandTests.java @@ -22,7 +22,10 @@ import org.junit.jupiter.api.Test; +import org.springframework.boot.loader.jarmode.JarModeErrorException; + import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; /** * Tests for {@link ListLayersCommand}. @@ -39,9 +42,9 @@ void shouldListLayers() throws IOException { } @Test - void shouldPrintErrorWhenLayersAreNotEnabled() throws IOException { - TestPrintStream out = run(createArchive()); - assertThat(out).hasSameContentAsResource("list-layers-output-layers-disabled.txt"); + void shouldFailWhenLayersAreNotEnabled() { + assertThatExceptionOfType(JarModeErrorException.class).isThrownBy(() -> run(createArchive())) + .withMessage("Layers are not enabled"); } private TestPrintStream run(File archive) { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-tools/src/test/resources/org/springframework/boot/jarmode/tools/ExtractCommand-printErrorIfLayersAreNotEnabled.txt b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-tools/src/test/resources/org/springframework/boot/jarmode/tools/ExtractCommand-printErrorIfLayersAreNotEnabled.txt deleted file mode 100644 index 994354551a65..000000000000 --- a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-tools/src/test/resources/org/springframework/boot/jarmode/tools/ExtractCommand-printErrorIfLayersAreNotEnabled.txt +++ /dev/null @@ -1,2 +0,0 @@ -Error: Layers are not enabled - diff --git a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-tools/src/test/resources/org/springframework/boot/jarmode/tools/list-layers-output-layers-disabled.txt b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-tools/src/test/resources/org/springframework/boot/jarmode/tools/list-layers-output-layers-disabled.txt deleted file mode 100644 index 994354551a65..000000000000 --- a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-tools/src/test/resources/org/springframework/boot/jarmode/tools/list-layers-output-layers-disabled.txt +++ /dev/null @@ -1,2 +0,0 @@ -Error: Layers are not enabled - diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader-classic/src/main/java/org/springframework/boot/loader/jarmode/JarMode.java b/spring-boot-project/spring-boot-tools/spring-boot-loader-classic/src/main/java/org/springframework/boot/loader/jarmode/JarMode.java index 162e4a6a7396..b91fdf1f5464 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-loader-classic/src/main/java/org/springframework/boot/loader/jarmode/JarMode.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader-classic/src/main/java/org/springframework/boot/loader/jarmode/JarMode.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -36,7 +36,8 @@ public interface JarMode { * Run the jar in the given mode. * @param mode the mode to use * @param args any program arguments + * @throws JarModeErrorException on an error that should print a simple error message */ - void run(String mode, String[] args); + void run(String mode, String[] args) throws JarModeErrorException; } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader-classic/src/main/java/org/springframework/boot/loader/jarmode/JarModeErrorException.java b/spring-boot-project/spring-boot-tools/spring-boot-loader-classic/src/main/java/org/springframework/boot/loader/jarmode/JarModeErrorException.java new file mode 100644 index 000000000000..92f1720bdf24 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader-classic/src/main/java/org/springframework/boot/loader/jarmode/JarModeErrorException.java @@ -0,0 +1,36 @@ +/* + * Copyright 2012-2024 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.loader.jarmode; + +/** + * Simple {@link RuntimeException} used to fail the jar mode with a simple printed error + * message. + * + * @author Phillip Webb + * @since 3.3.7 + */ +public class JarModeErrorException extends RuntimeException { + + public JarModeErrorException(String message) { + super(message); + } + + public JarModeErrorException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader-classic/src/main/java/org/springframework/boot/loader/jarmode/JarModeLauncher.java b/spring-boot-project/spring-boot-tools/spring-boot-loader-classic/src/main/java/org/springframework/boot/loader/jarmode/JarModeLauncher.java index 600266a241be..1a774e513f52 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-loader-classic/src/main/java/org/springframework/boot/loader/jarmode/JarModeLauncher.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader-classic/src/main/java/org/springframework/boot/loader/jarmode/JarModeLauncher.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -31,11 +31,31 @@ public final class JarModeLauncher { static final String DISABLE_SYSTEM_EXIT = JarModeLauncher.class.getName() + ".DISABLE_SYSTEM_EXIT"; + static final String SUPPRESSED_SYSTEM_EXIT_CODE = JarModeLauncher.class.getName() + ".SUPPRESSED_SYSTEM_EXIT_CODE"; + private JarModeLauncher() { } public static void main(String[] args) { String mode = System.getProperty("jarmode"); + boolean disableSystemExit = Boolean.getBoolean(DISABLE_SYSTEM_EXIT); + try { + runJarMode(mode, args); + if (disableSystemExit) { + System.setProperty(SUPPRESSED_SYSTEM_EXIT_CODE, "0"); + } + } + catch (Throwable ex) { + printError(ex); + if (disableSystemExit) { + System.setProperty(SUPPRESSED_SYSTEM_EXIT_CODE, "1"); + return; + } + System.exit(1); + } + } + + private static void runJarMode(String mode, String[] args) { List candidates = SpringFactoriesLoader.loadFactories(JarMode.class, ClassUtils.getDefaultClassLoader()); for (JarMode candidate : candidates) { @@ -44,10 +64,17 @@ public static void main(String[] args) { return; } } - System.err.println("Unsupported jarmode '" + mode + "'"); - if (!Boolean.getBoolean(DISABLE_SYSTEM_EXIT)) { - System.exit(1); + throw new JarModeErrorException("Unsupported jarmode '" + mode + "'"); + } + + private static void printError(Throwable ex) { + if (ex instanceof JarModeErrorException) { + String message = ex.getMessage(); + System.err.println("Error: " + message); + System.err.println(); + return; } + ex.printStackTrace(); } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader-classic/src/main/java/org/springframework/boot/loader/jarmode/TestJarMode.java b/spring-boot-project/spring-boot-tools/spring-boot-loader-classic/src/main/java/org/springframework/boot/loader/jarmode/TestJarMode.java index 2e17175690a5..87ec48ed8c62 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-loader-classic/src/main/java/org/springframework/boot/loader/jarmode/TestJarMode.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader-classic/src/main/java/org/springframework/boot/loader/jarmode/TestJarMode.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -33,6 +33,12 @@ public boolean accepts(String mode) { @Override public void run(String mode, String[] args) { System.out.println("running in " + mode + " jar mode " + Arrays.asList(args)); + if (args.length > 0 && "error".equals(args[0])) { + throw new JarModeErrorException("error message"); + } + if (args.length > 0 && "fail".equals(args[0])) { + throw new IllegalStateException("bad"); + } } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader-classic/src/test/java/org/springframework/boot/loader/jarmode/LauncherJarModeTests.java b/spring-boot-project/spring-boot-tools/spring-boot-loader-classic/src/test/java/org/springframework/boot/loader/jarmode/LauncherJarModeTests.java index dfd4d671e012..71f4f3c20002 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-loader-classic/src/test/java/org/springframework/boot/loader/jarmode/LauncherJarModeTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader-classic/src/test/java/org/springframework/boot/loader/jarmode/LauncherJarModeTests.java @@ -55,6 +55,7 @@ void launchWhenJarModePropertyIsSetLaunchesJarMode(CapturedOutput out) throws Ex System.setProperty("jarmode", "test"); new TestLauncher().launch(new String[] { "boot" }); assertThat(out).contains("running in test jar mode [boot]"); + assertThat(System.getProperty(JarModeLauncher.SUPPRESSED_SYSTEM_EXIT_CODE)).isEqualTo("0"); } @Test @@ -62,6 +63,25 @@ void launchWhenJarModePropertyIsNotAcceptedThrowsException(CapturedOutput out) t System.setProperty("jarmode", "idontexist"); new TestLauncher().launch(new String[] { "boot" }); assertThat(out).contains("Unsupported jarmode 'idontexist'"); + assertThat(System.getProperty(JarModeLauncher.SUPPRESSED_SYSTEM_EXIT_CODE)).isEqualTo("1"); + } + + @Test + void launchWhenJarModeRunFailsWithErrorExceptionPrintsSimpleMessage(CapturedOutput out) throws Exception { + System.setProperty("jarmode", "test"); + new TestLauncher().launch(new String[] { "error" }); + assertThat(out).contains("running in test jar mode [error]"); + assertThat(out).contains("Error: error message"); + assertThat(System.getProperty(JarModeLauncher.SUPPRESSED_SYSTEM_EXIT_CODE)).isEqualTo("1"); + } + + @Test + void launchWhenJarModeRunFailsWithErrorExceptionPrintsStackTrace(CapturedOutput out) throws Exception { + System.setProperty("jarmode", "test"); + new TestLauncher().launch(new String[] { "fail" }); + assertThat(out).contains("running in test jar mode [fail]"); + assertThat(out).contains("java.lang.IllegalStateException: bad"); + assertThat(System.getProperty(JarModeLauncher.SUPPRESSED_SYSTEM_EXIT_CODE)).isEqualTo("1"); } private static final class TestLauncher extends Launcher { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jarmode/JarMode.java b/spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jarmode/JarMode.java index 162e4a6a7396..b91fdf1f5464 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jarmode/JarMode.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jarmode/JarMode.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -36,7 +36,8 @@ public interface JarMode { * Run the jar in the given mode. * @param mode the mode to use * @param args any program arguments + * @throws JarModeErrorException on an error that should print a simple error message */ - void run(String mode, String[] args); + void run(String mode, String[] args) throws JarModeErrorException; } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jarmode/JarModeErrorException.java b/spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jarmode/JarModeErrorException.java new file mode 100644 index 000000000000..92f1720bdf24 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jarmode/JarModeErrorException.java @@ -0,0 +1,36 @@ +/* + * Copyright 2012-2024 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.loader.jarmode; + +/** + * Simple {@link RuntimeException} used to fail the jar mode with a simple printed error + * message. + * + * @author Phillip Webb + * @since 3.3.7 + */ +public class JarModeErrorException extends RuntimeException { + + public JarModeErrorException(String message) { + super(message); + } + + public JarModeErrorException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/launch/JarModeRunner.java b/spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/launch/JarModeRunner.java index 4805a633d48c..a4ac27f1314d 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/launch/JarModeRunner.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/launch/JarModeRunner.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -19,6 +19,7 @@ import java.util.List; import org.springframework.boot.loader.jarmode.JarMode; +import org.springframework.boot.loader.jarmode.JarModeErrorException; import org.springframework.core.io.support.SpringFactoriesLoader; import org.springframework.util.ClassUtils; @@ -31,11 +32,31 @@ final class JarModeRunner { static final String DISABLE_SYSTEM_EXIT = JarModeRunner.class.getName() + ".DISABLE_SYSTEM_EXIT"; + static final String SUPPRESSED_SYSTEM_EXIT_CODE = JarModeRunner.class.getName() + ".SUPPRESSED_SYSTEM_EXIT_CODE"; + private JarModeRunner() { } static void main(String[] args) { String mode = System.getProperty("jarmode"); + boolean disableSystemExit = Boolean.getBoolean(DISABLE_SYSTEM_EXIT); + try { + runJarMode(mode, args); + if (disableSystemExit) { + System.setProperty(SUPPRESSED_SYSTEM_EXIT_CODE, "0"); + } + } + catch (Throwable ex) { + printError(ex); + if (disableSystemExit) { + System.setProperty(SUPPRESSED_SYSTEM_EXIT_CODE, "1"); + return; + } + System.exit(1); + } + } + + private static void runJarMode(String mode, String[] args) { List candidates = SpringFactoriesLoader.loadFactories(JarMode.class, ClassUtils.getDefaultClassLoader()); for (JarMode candidate : candidates) { @@ -44,10 +65,17 @@ static void main(String[] args) { return; } } - System.err.println("Unsupported jarmode '" + mode + "'"); - if (!Boolean.getBoolean(DISABLE_SYSTEM_EXIT)) { - System.exit(1); + throw new JarModeErrorException("Unsupported jarmode '" + mode + "'"); + } + + private static void printError(Throwable ex) { + if (ex instanceof JarModeErrorException) { + String message = ex.getMessage(); + System.err.println("Error: " + message); + System.err.println(); + return; } + ex.printStackTrace(); } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/jarmode/TestJarMode.java b/spring-boot-project/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/jarmode/TestJarMode.java index 2e17175690a5..87ec48ed8c62 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/jarmode/TestJarMode.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/jarmode/TestJarMode.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -33,6 +33,12 @@ public boolean accepts(String mode) { @Override public void run(String mode, String[] args) { System.out.println("running in " + mode + " jar mode " + Arrays.asList(args)); + if (args.length > 0 && "error".equals(args[0])) { + throw new JarModeErrorException("error message"); + } + if (args.length > 0 && "fail".equals(args[0])) { + throw new IllegalStateException("bad"); + } } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/launch/LauncherTests.java b/spring-boot-project/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/launch/LauncherTests.java index 2937d9e6752f..5c73dc68b8a2 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/launch/LauncherTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/launch/LauncherTests.java @@ -63,6 +63,7 @@ void launchWhenJarModePropertyIsSetLaunchesJarMode(CapturedOutput out) throws Ex System.setProperty("jarmode", "test"); new TestLauncher().launch(new String[] { "boot" }); assertThat(out).contains("running in test jar mode [boot]"); + assertThat(System.getProperty(JarModeRunner.SUPPRESSED_SYSTEM_EXIT_CODE)).isEqualTo("0"); } @Test @@ -70,6 +71,25 @@ void launchWhenJarModePropertyIsNotAcceptedThrowsException(CapturedOutput out) t System.setProperty("jarmode", "idontexist"); new TestLauncher().launch(new String[] { "boot" }); assertThat(out).contains("Unsupported jarmode 'idontexist'"); + assertThat(System.getProperty(JarModeRunner.SUPPRESSED_SYSTEM_EXIT_CODE)).isEqualTo("1"); + } + + @Test + void launchWhenJarModeRunFailsWithErrorExceptionPrintsSimpleMessage(CapturedOutput out) throws Exception { + System.setProperty("jarmode", "test"); + new TestLauncher().launch(new String[] { "error" }); + assertThat(out).contains("running in test jar mode [error]"); + assertThat(out).contains("Error: error message"); + assertThat(System.getProperty(JarModeRunner.SUPPRESSED_SYSTEM_EXIT_CODE)).isEqualTo("1"); + } + + @Test + void launchWhenJarModeRunFailsWithErrorExceptionPrintsStackTrace(CapturedOutput out) throws Exception { + System.setProperty("jarmode", "test"); + new TestLauncher().launch(new String[] { "fail" }); + assertThat(out).contains("running in test jar mode [fail]"); + assertThat(out).contains("java.lang.IllegalStateException: bad"); + assertThat(System.getProperty(JarModeRunner.SUPPRESSED_SYSTEM_EXIT_CODE)).isEqualTo("1"); } } From 26ab0fea81ddaae837d24f6b57ced7c56f41d67b Mon Sep 17 00:00:00 2001 From: Dmytro Nosan Date: Thu, 5 Dec 2024 11:55:57 +0200 Subject: [PATCH 096/203] Don't replace existing defaultRequestConfigCustomizer Update `HttpComponentsClientHttpRequestFactoryBuilder` to add to the existing `defaultRequestConfigCustomizer` rather than replace it. See gh-43429 --- .../HttpComponentsClientHttpRequestFactoryBuilder.java | 3 ++- .../HttpComponentsClientHttpRequestFactoryBuilderTests.java | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/http/client/HttpComponentsClientHttpRequestFactoryBuilder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/http/client/HttpComponentsClientHttpRequestFactoryBuilder.java index 19fbdfa7083d..ff8562ede025 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/http/client/HttpComponentsClientHttpRequestFactoryBuilder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/http/client/HttpComponentsClientHttpRequestFactoryBuilder.java @@ -182,7 +182,8 @@ public HttpComponentsClientHttpRequestFactoryBuilder withDefaultRequestConfigCus Consumer defaultRequestConfigCustomizer) { Assert.notNull(defaultRequestConfigCustomizer, "'defaultRequestConfigCustomizer' must not be null"); return new HttpComponentsClientHttpRequestFactoryBuilder(getCustomizers(), this.httpClientCustomizer, - this.connectionManagerCustomizer, this.socketConfigCustomizer, defaultRequestConfigCustomizer, + this.connectionManagerCustomizer, this.socketConfigCustomizer, + this.defaultRequestConfigCustomizer.andThen(defaultRequestConfigCustomizer), this.tlsSocketStrategyFactory); } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/http/client/HttpComponentsClientHttpRequestFactoryBuilderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/http/client/HttpComponentsClientHttpRequestFactoryBuilderTests.java index d9c80bab8048..bcdb86f7985d 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/http/client/HttpComponentsClientHttpRequestFactoryBuilderTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/http/client/HttpComponentsClientHttpRequestFactoryBuilderTests.java @@ -55,19 +55,25 @@ void withCustomizers() { TestCustomizer httpClientCustomizer2 = new TestCustomizer<>(); TestCustomizer connectionManagerCustomizer = new TestCustomizer<>(); TestCustomizer socketConfigCustomizer = new TestCustomizer<>(); + TestCustomizer socketConfigCustomizer1 = new TestCustomizer<>(); TestCustomizer defaultRequestConfigCustomizer = new TestCustomizer<>(); + TestCustomizer defaultRequestConfigCustomizer1 = new TestCustomizer<>(); ClientHttpRequestFactoryBuilder.httpComponents() .withHttpClientCustomizer(httpClientCustomizer1) .withHttpClientCustomizer(httpClientCustomizer2) .withConnectionManagerCustomizer(connectionManagerCustomizer) .withSocketConfigCustomizer(socketConfigCustomizer) + .withSocketConfigCustomizer(socketConfigCustomizer1) .withDefaultRequestConfigCustomizer(defaultRequestConfigCustomizer) + .withDefaultRequestConfigCustomizer(defaultRequestConfigCustomizer1) .build(); httpClientCustomizer1.assertCalled(); httpClientCustomizer2.assertCalled(); connectionManagerCustomizer.assertCalled(); socketConfigCustomizer.assertCalled(); + socketConfigCustomizer1.assertCalled(); defaultRequestConfigCustomizer.assertCalled(); + defaultRequestConfigCustomizer1.assertCalled(); } @Test From 3338c22372e8558e3d04e9be7a2321673e6aef5d Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Mon, 9 Dec 2024 09:43:13 -0800 Subject: [PATCH 097/203] Restore `build...` methods that don't need an SSL bundle Restore `buildConsumerProperties()` and `buildProducerProperties()` methods in `KafkaProperties` to make it more convenient to use them without an SSL bundle. Fixes gh-43300 --- .../boot/autoconfigure/kafka/KafkaProperties.java | 6 ------ .../boot/autoconfigure/kafka/KafkaPropertiesTests.java | 6 +++--- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaProperties.java index c74fa291f734..5ee77cd66ed2 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaProperties.java @@ -183,10 +183,7 @@ private Map buildCommonProperties(SslBundles sslBundles) { * default {@code kafkaConsumerFactory} bean. * @return the consumer properties initialized with the customizations defined on this * instance - * @deprecated since 3.2.0 for removal in 3.4.0 in favor of - * {@link #buildConsumerProperties(SslBundles)}} */ - @Deprecated(since = "3.2.0", forRemoval = true) public Map buildConsumerProperties() { return buildConsumerProperties(null); } @@ -213,10 +210,7 @@ public Map buildConsumerProperties(SslBundles sslBundles) { * default {@code kafkaProducerFactory} bean. * @return the producer properties initialized with the customizations defined on this * instance - * @deprecated since 3.2.0 for removal in 3.4.0 in favor of - * {@link #buildProducerProperties(SslBundles)}} */ - @Deprecated(since = "3.2.0", forRemoval = true) public Map buildProducerProperties() { return buildProducerProperties(null); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaPropertiesTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaPropertiesTests.java index dbd53fd59d81..f00ddd930bef 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaPropertiesTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaPropertiesTests.java @@ -80,7 +80,7 @@ void sslPemConfiguration() { properties.getSsl().setKeyStoreKey("-----BEGINkey"); properties.getSsl().setTrustStoreCertificates("-----BEGINtrust"); properties.getSsl().setKeyStoreCertificateChain("-----BEGINchain"); - Map consumerProperties = properties.buildConsumerProperties(null); + Map consumerProperties = properties.buildConsumerProperties(); assertThat(consumerProperties).containsEntry(SslConfigs.SSL_KEYSTORE_KEY_CONFIG, "-----BEGINkey"); assertThat(consumerProperties).containsEntry(SslConfigs.SSL_TRUSTSTORE_CERTIFICATES_CONFIG, "-----BEGINtrust"); assertThat(consumerProperties).containsEntry(SslConfigs.SSL_KEYSTORE_CERTIFICATE_CHAIN_CONFIG, @@ -103,7 +103,7 @@ void sslPropertiesWhenKeyStoreLocationAndKeySetShouldThrowException() { properties.getSsl().setKeyStoreKey("-----BEGIN"); properties.getSsl().setKeyStoreLocation(new ClassPathResource("ksLoc")); assertThatExceptionOfType(MutuallyExclusiveConfigurationPropertiesException.class) - .isThrownBy(() -> properties.buildConsumerProperties(null)); + .isThrownBy(() -> properties.buildConsumerProperties()); } @Test @@ -112,7 +112,7 @@ void sslPropertiesWhenTrustStoreLocationAndCertificatesSetShouldThrowException() properties.getSsl().setTrustStoreLocation(new ClassPathResource("tsLoc")); properties.getSsl().setTrustStoreCertificates("-----BEGIN"); assertThatExceptionOfType(MutuallyExclusiveConfigurationPropertiesException.class) - .isThrownBy(() -> properties.buildConsumerProperties(null)); + .isThrownBy(() -> properties.buildConsumerProperties()); } @Test From 55ffed4ee49eff0ad803e848c17b407974ffd29a Mon Sep 17 00:00:00 2001 From: Soby Chacko Date: Mon, 9 Dec 2024 12:50:45 -0500 Subject: [PATCH 098/203] Add dependency management for kafka-server Apache Kafka now ships a new module, kafka-server, since the 3.7.0 release. The `3.9.0` kafka-client introduced some breaking changes that require this dependecy for the `EmbeddedKafka` support in Spring for Apache Kafka. This commit adds this dependecny for Spring Boot based Spring Kafka projects. See gh-43450 --- spring-boot-project/spring-boot-dependencies/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 653705505196..74b69f5484f8 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -1098,6 +1098,7 @@ bom { "kafka-log4j-appender", "kafka-metadata", "kafka-raft", + "kafka-server", "kafka-server-common", "kafka-server-common" { classifier = "test" From fe9c9358cdec852d4eea2f65821ff10e85fb85d1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Dec 2024 19:10:02 +0000 Subject: [PATCH 099/203] Bump jfrog/setup-jfrog-cli from 4.4.3 to 4.5.0 Bumps [jfrog/setup-jfrog-cli](https://github.com/jfrog/setup-jfrog-cli) from 4.4.3 to 4.5.0. - [Release notes](https://github.com/jfrog/setup-jfrog-cli/releases) - [Commits](https://github.com/jfrog/setup-jfrog-cli/compare/e7cc33a01bc1b1df406bac8a1c4a409a34bdca0a...040913fd7ac2a2bcb29a7e963ea99e7c309d63e5) --- updated-dependencies: - dependency-name: jfrog/setup-jfrog-cli dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] See gh-43451 --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a77bd4779ac5..ab701e252a85 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -78,7 +78,7 @@ jobs: runs-on: ${{ vars.UBUNTU_SMALL || 'ubuntu-latest' }} steps: - name: Set up JFrog CLI - uses: jfrog/setup-jfrog-cli@e7cc33a01bc1b1df406bac8a1c4a409a34bdca0a # v4.4.3 + uses: jfrog/setup-jfrog-cli@040913fd7ac2a2bcb29a7e963ea99e7c309d63e5 # v4.5.0 env: JF_ENV_SPRING: ${{ vars.COMMERCIAL && secrets.COMMERCIAL_JF_ARTIFACTORY_SPRING || secrets.JF_ARTIFACTORY_SPRING }} - name: Promote open source build From 8171f041130ad2c452d46b86c7c158f249cf702a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Tue, 10 Dec 2024 07:33:03 +0100 Subject: [PATCH 100/203] Polish "Bump jfrog/setup-jfrog-cli from 4.4.3 to 4.5.0" See gh-43451 --- .github/actions/publish-gradle-plugin/action.yml | 2 +- .github/actions/sync-to-maven-central/action.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/publish-gradle-plugin/action.yml b/.github/actions/publish-gradle-plugin/action.yml index f133cf321c04..22fdbb3c7a80 100644 --- a/.github/actions/publish-gradle-plugin/action.yml +++ b/.github/actions/publish-gradle-plugin/action.yml @@ -21,7 +21,7 @@ runs: using: composite steps: - name: Set Up JFrog CLI - uses: jfrog/setup-jfrog-cli@e7cc33a01bc1b1df406bac8a1c4a409a34bdca0a # v4.4.3 + uses: jfrog/setup-jfrog-cli@040913fd7ac2a2bcb29a7e963ea99e7c309d63e5 # v4.5.0 env: JF_ENV_SPRING: ${{ inputs.jfrog-cli-config-token }} - name: Download Artifacts diff --git a/.github/actions/sync-to-maven-central/action.yml b/.github/actions/sync-to-maven-central/action.yml index af148ddff542..5acccb937998 100644 --- a/.github/actions/sync-to-maven-central/action.yml +++ b/.github/actions/sync-to-maven-central/action.yml @@ -20,7 +20,7 @@ runs: using: composite steps: - name: Set Up JFrog CLI - uses: jfrog/setup-jfrog-cli@e7cc33a01bc1b1df406bac8a1c4a409a34bdca0a # v4.4.3 + uses: jfrog/setup-jfrog-cli@040913fd7ac2a2bcb29a7e963ea99e7c309d63e5 # v4.5.0 env: JF_ENV_SPRING: ${{ inputs.jfrog-cli-config-token }} - name: Download Release Artifacts From a96b91fa3eabd2db3741d366618d9bed7c304831 Mon Sep 17 00:00:00 2001 From: Tran Ngoc Nhan Date: Sat, 7 Dec 2024 20:46:51 +0700 Subject: [PATCH 101/203] Fix logback javadoc See gh-43439 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 74b69f5484f8..6ebb03bb412c 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -1217,7 +1217,7 @@ bom { } links { site("https://logback.qos.ch") - javadoc("https://logback.qos.ch/apidocs", "ch.qos.logback") + javadoc("https://logback.qos.ch/apidocs/ch.qos.logback.core", "ch.qos.logback") } } library("Lombok", "1.18.36") { From e2cf9e105c69f35ac6e38c994ecd526dee1b7883 Mon Sep 17 00:00:00 2001 From: Moritz Halbritter Date: Tue, 10 Dec 2024 14:22:01 +0100 Subject: [PATCH 102/203] Respect profiles when listing running Docker Compose containers Closes gh-40139 --- .../DefaultDockerComposeIntegrationTests.java | 116 ++++++++++++++++++ .../boot/docker/compose/core/profiles.yaml | 17 +++ .../docker/compose/core/DockerCliCommand.java | 5 +- .../compose/core/DockerCliCommandTests.java | 4 +- 4 files changed, 138 insertions(+), 4 deletions(-) create mode 100644 spring-boot-project/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/core/DefaultDockerComposeIntegrationTests.java create mode 100644 spring-boot-project/spring-boot-docker-compose/src/dockerTest/resources/org/springframework/boot/docker/compose/core/profiles.yaml diff --git a/spring-boot-project/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/core/DefaultDockerComposeIntegrationTests.java b/spring-boot-project/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/core/DefaultDockerComposeIntegrationTests.java new file mode 100644 index 000000000000..2021f0af6a5f --- /dev/null +++ b/spring-boot-project/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/core/DefaultDockerComposeIntegrationTests.java @@ -0,0 +1,116 @@ +/* + * Copyright 2012-2024 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.docker.compose.core; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.Duration; +import java.util.List; +import java.util.Set; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import org.springframework.boot.logging.LogLevel; +import org.springframework.boot.testsupport.container.DisabledIfDockerUnavailable; +import org.springframework.boot.testsupport.container.TestImage; +import org.springframework.boot.testsupport.process.DisabledIfProcessUnavailable; +import org.springframework.core.io.ClassPathResource; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link DefaultDockerCompose}. + * + * @author Moritz Halbritter + */ +@DisabledIfDockerUnavailable +@DisabledIfProcessUnavailable({ "docker", "compose" }) +class DefaultDockerComposeIntegrationTests { + + @Test + void shouldWorkWithProfiles(@TempDir Path tempDir) throws IOException { + // Profile 1 contains redis1 and redis3 + // Profile 2 contains redis2 and redis3 + File composeFile = createComposeFile(tempDir, "profiles.yaml").toFile(); + DefaultDockerCompose dockerComposeWithProfile1 = new DefaultDockerCompose( + new DockerCli(tempDir.toFile(), DockerComposeFile.of(composeFile), Set.of("1")), null); + DefaultDockerCompose dockerComposeWithProfile2 = new DefaultDockerCompose( + new DockerCli(tempDir.toFile(), DockerComposeFile.of(composeFile), Set.of("2")), null); + DefaultDockerCompose dockerComposeWithAllProfiles = new DefaultDockerCompose( + new DockerCli(tempDir.toFile(), DockerComposeFile.of(composeFile), Set.of("1", "2")), null); + dockerComposeWithAllProfiles.up(LogLevel.DEBUG); + try { + List runningServicesProfile1 = dockerComposeWithProfile1.getRunningServices(); + assertThatContainsService(runningServicesProfile1, "redis1"); + assertThatDoesNotContainService(runningServicesProfile1, "redis2"); + assertThatContainsService(runningServicesProfile1, "redis3"); + + List runningServicesProfile2 = dockerComposeWithProfile2.getRunningServices(); + assertThatDoesNotContainService(runningServicesProfile2, "redis1"); + assertThatContainsService(runningServicesProfile2, "redis2"); + assertThatContainsService(runningServicesProfile2, "redis3"); + + // Assert that redis3 is started only once and is shared between profile 1 and + // profile 2 + assertThat(dockerComposeWithAllProfiles.getRunningServices()).hasSize(3); + RunningService redis3Profile1 = findService(runningServicesProfile1, "redis3"); + RunningService redis3Profile2 = findService(runningServicesProfile2, "redis3"); + assertThat(redis3Profile1).isNotNull(); + assertThat(redis3Profile2).isNotNull(); + assertThat(redis3Profile1.name()).isEqualTo(redis3Profile2.name()); + } + finally { + dockerComposeWithAllProfiles.down(Duration.ofSeconds(10)); + } + } + + private RunningService findService(List runningServices, String serviceName) { + for (RunningService runningService : runningServices) { + if (runningService.name().contains(serviceName)) { + return runningService; + } + } + return null; + } + + private void assertThatDoesNotContainService(List runningServices, String service) { + if (findService(runningServices, service) != null) { + Assertions.fail("Did not expect service '%s', but found it in [%s]", service, runningServices); + } + } + + private void assertThatContainsService(List runningServices, String service) { + if (findService(runningServices, service) == null) { + Assertions.fail("Expected service '%s', but hasn't been found in [%s]", service, runningServices); + } + } + + private static Path createComposeFile(Path tempDir, String resource) throws IOException { + String composeFileTemplate = new ClassPathResource(resource, DockerCliIntegrationTests.class) + .getContentAsString(StandardCharsets.UTF_8); + String content = composeFileTemplate.replace("{imageName}", TestImage.REDIS.toString()); + Path composeFile = tempDir.resolve(resource); + Files.writeString(composeFile, content); + return composeFile; + } + +} diff --git a/spring-boot-project/spring-boot-docker-compose/src/dockerTest/resources/org/springframework/boot/docker/compose/core/profiles.yaml b/spring-boot-project/spring-boot-docker-compose/src/dockerTest/resources/org/springframework/boot/docker/compose/core/profiles.yaml new file mode 100644 index 000000000000..c32fb2b121e6 --- /dev/null +++ b/spring-boot-project/spring-boot-docker-compose/src/dockerTest/resources/org/springframework/boot/docker/compose/core/profiles.yaml @@ -0,0 +1,17 @@ +services: + redis1: + profiles: + - '1' + image: '{imageName}' + ports: + - '6379' + redis2: + profiles: + - '2' + image: '{imageName}' + ports: + - '6379' + redis3: + image: '{imageName}' + ports: + - '6379' diff --git a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DockerCliCommand.java b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DockerCliCommand.java index feb2d8dd6aa8..9c9f588ecfc2 100644 --- a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DockerCliCommand.java +++ b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DockerCliCommand.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -151,7 +151,8 @@ static final class ComposeConfig extends DockerCliCommand> { ComposePs() { - super(Type.DOCKER_COMPOSE, DockerCliComposePsResponse.class, true, "ps", "--format=json"); + super(Type.DOCKER_COMPOSE, DockerCliComposePsResponse.class, true, "ps", "--orphans=false", + "--format=json"); } } diff --git a/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/core/DockerCliCommandTests.java b/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/core/DockerCliCommandTests.java index 4ed1d983bd17..c1aa4abf6793 100644 --- a/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/core/DockerCliCommandTests.java +++ b/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/core/DockerCliCommandTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -62,7 +62,7 @@ void composeConfig() { void composePs() { DockerCliCommand command = new DockerCliCommand.ComposePs(); assertThat(command.getType()).isEqualTo(DockerCliCommand.Type.DOCKER_COMPOSE); - assertThat(command.getCommand()).containsExactly("ps", "--format=json"); + assertThat(command.getCommand()).containsExactly("ps", "--orphans=false", "--format=json"); assertThat(command.deserialize("[]")).isInstanceOf(List.class); } From bed68daa130edd65ae74d7b2079cc6b4eae88e5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Tue, 10 Dec 2024 15:06:32 +0100 Subject: [PATCH 103/203] Upgrade to Zipkin Reporter 3.4.3 Closes gh-43462 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 6ebb03bb412c..5df6b04a465d 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -104,7 +104,7 @@ bom { .formatted(version.major(), version.minor())) } } - library("Zipkin Reporter", "3.4.2") { + library("Zipkin Reporter", "3.4.3") { group("io.zipkin.reporter2") { imports = [ "zipkin-reporter-bom" From 7486c27cdd59e542d631b9897acaf7c60f01fe7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Tue, 10 Dec 2024 15:06:37 +0100 Subject: [PATCH 104/203] Upgrade to jOOQ 3.19.16 Closes gh-43463 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 5df6b04a465d..d69892a703c2 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -994,7 +994,7 @@ bom { ] } } - library("jOOQ", "3.19.15") { + library("jOOQ", "3.19.16") { group("org.jooq") { modules = [ "jooq", From dcf8b31eda2ff48340124f8e676331a0d5b7d57e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Tue, 10 Dec 2024 15:06:37 +0100 Subject: [PATCH 105/203] Upgrade to Micrometer 1.13.9 Closes gh-43388 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index d69892a703c2..10ed00af954d 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -1417,7 +1417,7 @@ bom { releaseNotes("https://github.com/apache/maven-war-plugin/releases/tag/maven-war-plugin-{version}") } } - library("Micrometer", "1.13.9-SNAPSHOT") { + library("Micrometer", "1.13.9") { considerSnapshots() group("io.micrometer") { modules = [ From 8a473a40987b644e8df59b6d9a25c931788b639d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Tue, 10 Dec 2024 15:06:37 +0100 Subject: [PATCH 106/203] Upgrade to Micrometer Tracing 1.3.7 Closes gh-43389 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 10ed00af954d..9989468c6053 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -1441,7 +1441,7 @@ bom { releaseNotes("https://github.com/micrometer-metrics/micrometer/releases/tag/v{version}") } } - library("Micrometer Tracing", "1.3.7-SNAPSHOT") { + library("Micrometer Tracing", "1.3.7") { considerSnapshots() group("io.micrometer") { imports = [ From 6a68faaf9c1832f11a9bdbf978f1807514f014c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Tue, 10 Dec 2024 15:06:37 +0100 Subject: [PATCH 107/203] Upgrade to Reactor Bom 2023.0.13 Closes gh-43390 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 9989468c6053..729bde3fcece 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -1893,7 +1893,7 @@ bom { ] } } - library("Reactor Bom", "2023.0.13-SNAPSHOT") { + library("Reactor Bom", "2023.0.13") { considerSnapshots() calendarName = "Reactor" group("io.projectreactor") { From 65cedf6bc576e045fe8a0a8e75949da3e6994039 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Tue, 10 Dec 2024 15:06:41 +0100 Subject: [PATCH 108/203] Upgrade to Thymeleaf 3.1.3.RELEASE Closes gh-43464 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 729bde3fcece..86f11d6bb14e 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2398,7 +2398,7 @@ bom { releaseNotes("https://github.com/testcontainers/testcontainers-java/releases/tag/{version}") } } - library("Thymeleaf", "3.1.2.RELEASE") { + library("Thymeleaf", "3.1.3.RELEASE") { group("org.thymeleaf") { modules = [ "thymeleaf", From df94a86924227448ef8c7ac476f34f04996c281d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Tue, 10 Dec 2024 15:06:45 +0100 Subject: [PATCH 109/203] Upgrade to Thymeleaf Extras SpringSecurity 3.1.3.RELEASE Closes gh-43465 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 86f11d6bb14e..c9f0a189ee0e 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2419,7 +2419,7 @@ bom { ] } } - library("Thymeleaf Extras SpringSecurity", "3.1.2.RELEASE") { + library("Thymeleaf Extras SpringSecurity", "3.1.3.RELEASE") { group("org.thymeleaf.extras") { modules = [ "thymeleaf-extras-springsecurity6" From 6d74fc325336944b7a92aa9d5feca389c0116546 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Tue, 10 Dec 2024 15:06:50 +0100 Subject: [PATCH 110/203] Upgrade to Tomcat 10.1.34 Closes gh-43466 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 2635deac6258..682b2e319dcc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -21,6 +21,6 @@ nativeBuildToolsVersion=0.10.4 snakeYamlVersion=2.2 springFrameworkVersion=6.1.16-SNAPSHOT springFramework60xVersion=6.0.23 -tomcatVersion=10.1.33 +tomcatVersion=10.1.34 kotlin.stdlib.default.dependency=false From a59937b8b867664ab02e629add944710f4b03738 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Tue, 10 Dec 2024 15:14:14 +0100 Subject: [PATCH 111/203] Upgrade to Zipkin Reporter 3.4.3 Closes gh-43467 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 99cae69c44c0..10829b2c4ccc 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -104,7 +104,7 @@ bom { .formatted(version.major(), version.minor())) } } - library("Zipkin Reporter", "3.4.2") { + library("Zipkin Reporter", "3.4.3") { group("io.zipkin.reporter2") { imports = [ "zipkin-reporter-bom" From bd53ba3846a200437bf5003b848e07d738dc2ac1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Tue, 10 Dec 2024 15:14:20 +0100 Subject: [PATCH 112/203] Upgrade to jOOQ 3.19.16 Closes gh-43468 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 10829b2c4ccc..54eb95f7bdda 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -1011,7 +1011,7 @@ bom { ] } } - library("jOOQ", "3.19.15") { + library("jOOQ", "3.19.16") { group("org.jooq") { modules = [ "jooq", From 4fa33183ba27d9a884fcd4f76c58cc98d5674b2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Tue, 10 Dec 2024 15:14:20 +0100 Subject: [PATCH 113/203] Upgrade to Micrometer 1.14.2 Closes gh-43408 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 54eb95f7bdda..506959e39382 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -1442,7 +1442,7 @@ bom { releaseNotes("https://github.com/apache/maven-war-plugin/releases/tag/maven-war-plugin-{version}") } } - library("Micrometer", "1.14.2-SNAPSHOT") { + library("Micrometer", "1.14.2") { considerSnapshots() group("io.micrometer") { modules = [ From 1a9fc9b06c94d93292a5bff963f306c712676af5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Tue, 10 Dec 2024 15:14:20 +0100 Subject: [PATCH 114/203] Upgrade to Micrometer Tracing 1.4.1 Closes gh-43409 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 506959e39382..bf99743250f6 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -1466,7 +1466,7 @@ bom { releaseNotes("https://github.com/micrometer-metrics/micrometer/releases/tag/v{version}") } } - library("Micrometer Tracing", "1.4.1-SNAPSHOT") { + library("Micrometer Tracing", "1.4.1") { considerSnapshots() group("io.micrometer") { imports = [ From 7e94839c7c5f152eb92369b6a8a2382628516fa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Tue, 10 Dec 2024 15:14:21 +0100 Subject: [PATCH 115/203] Upgrade to Reactor Bom 2024.0.1 Closes gh-43410 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index bf99743250f6..fa5f6675d0fb 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -1876,7 +1876,7 @@ bom { ] } } - library("Reactor Bom", "2024.0.1-SNAPSHOT") { + library("Reactor Bom", "2024.0.1") { considerSnapshots() calendarName = "Reactor" group("io.projectreactor") { From 922ff4f252c409d83e258720c73149462c0dfebe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Tue, 10 Dec 2024 15:14:25 +0100 Subject: [PATCH 116/203] Upgrade to Thymeleaf 3.1.3.RELEASE Closes gh-43469 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index fa5f6675d0fb..7888d3985ee6 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2392,7 +2392,7 @@ bom { javadoc("https://javadoc.io/doc/com.redis/testcontainers-redis/{version}", "com.redis.testcontainers") } } - library("Thymeleaf", "3.1.2.RELEASE") { + library("Thymeleaf", "3.1.3.RELEASE") { group("org.thymeleaf") { modules = [ "thymeleaf", From f17ba516fa9e316f0daa108065dbb428bc283bbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Tue, 10 Dec 2024 15:14:30 +0100 Subject: [PATCH 117/203] Upgrade to Thymeleaf Extras SpringSecurity 3.1.3.RELEASE Closes gh-43470 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 7888d3985ee6..f5156e0e4610 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2413,7 +2413,7 @@ bom { ] } } - library("Thymeleaf Extras SpringSecurity", "3.1.2.RELEASE") { + library("Thymeleaf Extras SpringSecurity", "3.1.3.RELEASE") { group("org.thymeleaf.extras") { modules = [ "thymeleaf-extras-springsecurity6" From 3b2f0dfc69d5e760bc054b1125ffc22f27596d93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Tue, 10 Dec 2024 15:14:34 +0100 Subject: [PATCH 118/203] Upgrade to Tomcat 10.1.34 Closes gh-43471 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index adc886a5a0c1..511346aad001 100644 --- a/gradle.properties +++ b/gradle.properties @@ -21,6 +21,6 @@ nativeBuildToolsVersion=0.10.4 snakeYamlVersion=2.3 springFrameworkVersion=6.2.1-SNAPSHOT springFramework60xVersion=6.0.23 -tomcatVersion=10.1.33 +tomcatVersion=10.1.34 kotlin.stdlib.default.dependency=false From f65336ca56a997f168ac974740fe2de39631b650 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Tue, 10 Dec 2024 16:28:34 +0100 Subject: [PATCH 119/203] Fix compilation failure on merge --- .../DefaultDockerComposeIntegrationTests.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/spring-boot-project/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/core/DefaultDockerComposeIntegrationTests.java b/spring-boot-project/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/core/DefaultDockerComposeIntegrationTests.java index 2021f0af6a5f..61a52019d27a 100644 --- a/spring-boot-project/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/core/DefaultDockerComposeIntegrationTests.java +++ b/spring-boot-project/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/core/DefaultDockerComposeIntegrationTests.java @@ -22,6 +22,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.time.Duration; +import java.util.Collections; import java.util.List; import java.util.Set; @@ -29,6 +30,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; +import org.springframework.boot.docker.compose.core.DockerCli.DockerComposeOptions; import org.springframework.boot.logging.LogLevel; import org.springframework.boot.testsupport.container.DisabledIfDockerUnavailable; import org.springframework.boot.testsupport.container.TestImage; @@ -51,12 +53,15 @@ void shouldWorkWithProfiles(@TempDir Path tempDir) throws IOException { // Profile 1 contains redis1 and redis3 // Profile 2 contains redis2 and redis3 File composeFile = createComposeFile(tempDir, "profiles.yaml").toFile(); - DefaultDockerCompose dockerComposeWithProfile1 = new DefaultDockerCompose( - new DockerCli(tempDir.toFile(), DockerComposeFile.of(composeFile), Set.of("1")), null); - DefaultDockerCompose dockerComposeWithProfile2 = new DefaultDockerCompose( - new DockerCli(tempDir.toFile(), DockerComposeFile.of(composeFile), Set.of("2")), null); - DefaultDockerCompose dockerComposeWithAllProfiles = new DefaultDockerCompose( - new DockerCli(tempDir.toFile(), DockerComposeFile.of(composeFile), Set.of("1", "2")), null); + DefaultDockerCompose dockerComposeWithProfile1 = new DefaultDockerCompose(new DockerCli(tempDir.toFile(), + new DockerComposeOptions(DockerComposeFile.of(composeFile), Set.of("1"), Collections.emptyList())), + null); + DefaultDockerCompose dockerComposeWithProfile2 = new DefaultDockerCompose(new DockerCli(tempDir.toFile(), + new DockerComposeOptions(DockerComposeFile.of(composeFile), Set.of("2"), Collections.emptyList())), + null); + DefaultDockerCompose dockerComposeWithAllProfiles = new DefaultDockerCompose(new DockerCli(tempDir.toFile(), + new DockerComposeOptions(DockerComposeFile.of(composeFile), Set.of("1", "2"), Collections.emptyList())), + null); dockerComposeWithAllProfiles.up(LogLevel.DEBUG); try { List runningServicesProfile1 = dockerComposeWithProfile1.getRunningServices(); From 8dfde8625cf3ce9d9b7412252d49d292e2a9506e Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 10 Dec 2024 09:38:12 -0800 Subject: [PATCH 120/203] Start building against Spring Batch 5.1.3 snapshots See gh-43474 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index c9f0a189ee0e..fd7979de6757 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2132,7 +2132,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-authorization-server/releases/tag/{version}") } } - library("Spring Batch", "5.1.2") { + library("Spring Batch", "5.1.3-SNAPSHOT") { considerSnapshots() group("org.springframework.batch") { imports = [ From 60217e0894523eb284516b70bfce2fd23bc43711 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 10 Dec 2024 09:38:16 -0800 Subject: [PATCH 121/203] Start building against Spring HATEOAS 2.3.4 snapshots See gh-43475 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index fd7979de6757..24d938bc49d4 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2201,7 +2201,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-graphql/releases/tag/v{version}") } } - library("Spring HATEOAS", "2.3.3") { + library("Spring HATEOAS", "2.3.4-SNAPSHOT") { considerSnapshots() group("org.springframework.hateoas") { modules = [ From 8ab03e0495f91856e344375d69e2fe00391d713b Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 10 Dec 2024 09:38:21 -0800 Subject: [PATCH 122/203] Start building against Spring Integration 6.3.7 snapshots See gh-43476 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 24d938bc49d4..0725b5a94124 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2218,7 +2218,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-hateoas/releases/tag/{version}") } } - library("Spring Integration", "6.3.6") { + library("Spring Integration", "6.3.7-SNAPSHOT") { considerSnapshots() group("org.springframework.integration") { imports = [ From 6344c4767f8f6c000f85b5cc5c4b751aec33dcad Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 10 Dec 2024 09:38:21 -0800 Subject: [PATCH 123/203] Start building against Spring Session 3.3.5 snapshots See gh-43397 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 0725b5a94124..79445b7e30fc 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2337,7 +2337,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-security/releases/tag/{version}") } } - library("Spring Session", "3.3.4-SNAPSHOT") { + library("Spring Session", "3.3.5-SNAPSHOT") { considerSnapshots() prohibit { startsWith(["Apple-", "Bean-", "Corn-", "Dragonfruit-"]) From d815009aca2db904925e513fe88f095867593377 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 10 Dec 2024 09:42:14 -0800 Subject: [PATCH 124/203] Start building against Spring Batch 5.2.1 snapshots See gh-43477 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index f5156e0e4610..4bce67642b90 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2115,7 +2115,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-authorization-server/releases/tag/{version}") } } - library("Spring Batch", "5.2.0") { + library("Spring Batch", "5.2.1-SNAPSHOT") { considerSnapshots() group("org.springframework.batch") { imports = [ From 48d51bda1d946cfd19d76d024fa26eaaedef5d95 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 10 Dec 2024 09:42:18 -0800 Subject: [PATCH 125/203] Start building against Spring HATEOAS 2.4.1 snapshots See gh-43478 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 4bce67642b90..ec432a89ef88 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2184,7 +2184,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-graphql/releases/tag/v{version}") } } - library("Spring HATEOAS", "2.4.0") { + library("Spring HATEOAS", "2.4.1-SNAPSHOT") { considerSnapshots() group("org.springframework.hateoas") { modules = [ From 5ea9c741c80a039d19e646d33d5518937fb16450 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 10 Dec 2024 13:00:57 -0800 Subject: [PATCH 126/203] Don't duplicate lines when issue has release notes link --- .../springframework/boot/build/bom/bomr/MoveToSnapshots.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/MoveToSnapshots.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/MoveToSnapshots.java index dde8daabc0dd..2981277eb2d2 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/MoveToSnapshots.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/MoveToSnapshots.java @@ -87,7 +87,9 @@ protected String issueBody(Upgrade upgrade, Issue existingUpgrade) { if (releaseNotesLink != null) { lines.add("Upgrade to [%s](%s).".formatted(description, releaseNotesLink)); } - lines.add("Upgrade to %s.".formatted(description)); + else { + lines.add("Upgrade to %s.".formatted(description)); + } if (existingUpgrade != null) { lines.add("Supersedes #" + existingUpgrade.getNumber()); } From 123502b8d77a0b4e2f222e3e5ed1ad96f6effb37 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 10 Dec 2024 13:14:20 -0800 Subject: [PATCH 127/203] Restore use of fixed version when calling docker APIs Update `DockerApi` so that calls are made using a fixed version. For most calls this will be `v1.24`, however, for calls with a platform we must use the `v1.41`. When possible, we check that the Docker version in use meets the required minimum, however, if we can't detect the running version we now proceed and let the actual API call fail. This is due to the fact that the `/_ping` endpoint may not always be available. For example, it is restricted when building from a BitBucket CI pipeline. Fixes gh-43452 --- .../buildpack/platform/docker/DockerApi.java | 41 ++++++++------ .../platform/docker/DockerApiTests.java | 54 ++++++++++++------- 2 files changed, 61 insertions(+), 34 deletions(-) diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/DockerApi.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/DockerApi.java index 083d32348d03..e5659f9bce4c 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/DockerApi.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/DockerApi.java @@ -64,9 +64,11 @@ public class DockerApi { private static final List FORCE_PARAMS = Collections.unmodifiableList(Arrays.asList("force", "1")); - static final ApiVersion MINIMUM_API_VERSION = ApiVersion.of(1, 24); + static final ApiVersion API_VERSION = ApiVersion.of(1, 24); - static final ApiVersion MINIMUM_PLATFORM_API_VERSION = ApiVersion.of(1, 41); + static final ApiVersion PLATFORM_API_VERSION = ApiVersion.of(1, 41); + + static final ApiVersion UNKNOWN_API_VERSION = ApiVersion.of(0, 0); static final String API_VERSION_HEADER_NAME = "API-Version"; @@ -123,12 +125,17 @@ private JsonStream jsonStream() { } private URI buildUrl(String path, Collection params) { - return buildUrl(path, (params != null) ? params.toArray() : null); + return buildUrl(API_VERSION, path, (params != null) ? params.toArray() : null); } private URI buildUrl(String path, Object... params) { + return buildUrl(API_VERSION, path, params); + } + + private URI buildUrl(ApiVersion apiVersion, String path, Object... params) { + verifyApiVersion(apiVersion); try { - URIBuilder builder = new URIBuilder("/v" + getApiVersion() + path); + URIBuilder builder = new URIBuilder("/v" + apiVersion + path); int param = 0; while (param < params.length) { builder.addParameter(Objects.toString(params[param++]), Objects.toString(params[param++])); @@ -140,10 +147,11 @@ private URI buildUrl(String path, Object... params) { } } - private void verifyApiVersionForPlatform(ImagePlatform platform) { - Assert.isTrue(platform == null || getApiVersion().supports(MINIMUM_PLATFORM_API_VERSION), - () -> "Docker API version must be at least " + MINIMUM_PLATFORM_API_VERSION - + " to support the 'imagePlatform' option, but current API version is " + getApiVersion()); + private void verifyApiVersion(ApiVersion minimumVersion) { + ApiVersion actualVersion = getApiVersion(); + Assert.state(actualVersion.equals(UNKNOWN_API_VERSION) || actualVersion.supports(minimumVersion), + () -> "Docker API version must be at least " + minimumVersion + + " to support this feature, but current API version is " + actualVersion); } private ApiVersion getApiVersion() { @@ -213,9 +221,8 @@ public Image pull(ImageReference reference, ImagePlatform platform, UpdateListener listener, String registryAuth) throws IOException { Assert.notNull(reference, "Reference must not be null"); Assert.notNull(listener, "Listener must not be null"); - verifyApiVersionForPlatform(platform); URI createUri = (platform != null) - ? buildUrl("/images/create", "fromImage", reference, "platform", platform) + ? buildUrl(PLATFORM_API_VERSION, "/images/create", "fromImage", reference, "platform", platform) : buildUrl("/images/create", "fromImage", reference); DigestCaptureUpdateListener digestCapture = new DigestCaptureUpdateListener(); listener.onStart(); @@ -226,7 +233,7 @@ public Image pull(ImageReference reference, ImagePlatform platform, listener.onUpdate(event); }); } - return inspect(reference); + return inspect((platform != null) ? PLATFORM_API_VERSION : API_VERSION, reference); } finally { listener.onFinish(); @@ -353,8 +360,12 @@ public void remove(ImageReference reference, boolean force) throws IOException { * @throws IOException on IO error */ public Image inspect(ImageReference reference) throws IOException { + return inspect(API_VERSION, reference); + } + + private Image inspect(ApiVersion apiVersion, ImageReference reference) throws IOException { Assert.notNull(reference, "Reference must not be null"); - URI imageUri = buildUrl("/images/" + reference + "/json"); + URI imageUri = buildUrl(apiVersion, "/images/" + reference + "/json"); try (Response response = http().get(imageUri)) { return Image.of(response.getContent()); } @@ -401,8 +412,8 @@ public ContainerReference create(ContainerConfig config, ImagePlatform platform, } private ContainerReference createContainer(ContainerConfig config, ImagePlatform platform) throws IOException { - verifyApiVersionForPlatform(platform); - URI createUri = (platform != null) ? buildUrl("/containers/create", "platform", platform) + URI createUri = (platform != null) + ? buildUrl(PLATFORM_API_VERSION, "/containers/create", "platform", platform) : buildUrl("/containers/create"); try (Response response = http().post(createUri, "application/json", config::writeTo)) { return ContainerReference @@ -524,7 +535,7 @@ ApiVersion getApiVersion() { catch (Exception ex) { // fall through to return default value } - return MINIMUM_API_VERSION; + return UNKNOWN_API_VERSION; } catch (URISyntaxException ex) { throw new IllegalStateException(ex); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/DockerApiTests.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/DockerApiTests.java index b12bf7f2f646..2f717e44b620 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/DockerApiTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/DockerApiTests.java @@ -22,6 +22,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.net.URI; +import java.net.URISyntaxException; import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; @@ -87,17 +88,19 @@ @ExtendWith(MockitoExtension.class) class DockerApiTests { - private static final String API_URL = "/v" + DockerApi.MINIMUM_API_VERSION; + private static final String API_URL = "/v" + DockerApi.API_VERSION; + + private static final String PLATFORM_API_URL = "/v" + DockerApi.PLATFORM_API_VERSION; public static final String PING_URL = "/_ping"; private static final String IMAGES_URL = API_URL + "/images"; - private static final String IMAGES_1_41_URL = "/v" + ApiVersion.of(1, 41) + "/images"; + private static final String PLATFORM_IMAGES_URL = PLATFORM_API_URL + "/images"; private static final String CONTAINERS_URL = API_URL + "/containers"; - private static final String CONTAINERS_1_41_URL = "/v" + ApiVersion.of(1, 41) + "/containers"; + private static final String PLATFORM_CONTAINERS_URL = PLATFORM_API_URL + "/containers"; private static final String VOLUMES_URL = API_URL + "/volumes"; @@ -235,9 +238,9 @@ void pullWithRegistryAuthPullsImageAndProducesEvents() throws Exception { void pullWithPlatformPullsImageAndProducesEvents() throws Exception { ImageReference reference = ImageReference.of("gcr.io/paketo-buildpacks/builder:base"); ImagePlatform platform = ImagePlatform.of("linux/arm64/v1"); - URI createUri = new URI(IMAGES_1_41_URL + URI createUri = new URI(PLATFORM_IMAGES_URL + "/create?fromImage=gcr.io%2Fpaketo-buildpacks%2Fbuilder%3Abase&platform=linux%2Farm64%2Fv1"); - URI imageUri = new URI(IMAGES_1_41_URL + "/gcr.io/paketo-buildpacks/builder:base/json"); + URI imageUri = new URI(PLATFORM_IMAGES_URL + "/gcr.io/paketo-buildpacks/builder:base/json"); given(http().head(eq(new URI(PING_URL)))) .willReturn(responseWithHeaders(new BasicHeader(DockerApi.API_VERSION_HEADER_NAME, "1.41"))); given(http().post(eq(createUri), isNull())).willReturn(responseOf("pull-stream.json")); @@ -254,9 +257,9 @@ void pullWithPlatformPullsImageAndProducesEvents() throws Exception { void pullWithPlatformAndInsufficientApiVersionThrowsException() throws Exception { ImageReference reference = ImageReference.of("gcr.io/paketo-buildpacks/builder:base"); ImagePlatform platform = ImagePlatform.of("linux/arm64/v1"); - given(http().head(eq(new URI(PING_URL)))).willReturn(responseWithHeaders( - new BasicHeader(DockerApi.API_VERSION_HEADER_NAME, DockerApi.MINIMUM_API_VERSION))); - assertThatIllegalArgumentException().isThrownBy(() -> this.api.pull(reference, platform, this.pullListener)) + given(http().head(eq(new URI(PING_URL)))).willReturn( + responseWithHeaders(new BasicHeader(DockerApi.API_VERSION_HEADER_NAME, DockerApi.API_VERSION))); + assertThatIllegalStateException().isThrownBy(() -> this.api.pull(reference, platform, this.pullListener)) .withMessageContaining("must be at least 1.41") .withMessageContaining("current API version is 1.24"); } @@ -583,12 +586,23 @@ void createWhenHasContentContainerWithContent() throws Exception { @Test void createWithPlatformCreatesContainer() throws Exception { + createWithPlatform("1.41"); + } + + @Test + void createWithPlatformAndUnknownApiVersionAttemptsCreate() throws Exception { + createWithPlatform(null); + } + + private void createWithPlatform(String apiVersion) throws IOException, URISyntaxException { ImageReference imageReference = ImageReference.of("ubuntu:bionic"); ContainerConfig config = ContainerConfig.of(imageReference, (update) -> update.withCommand("/bin/bash")); ImagePlatform platform = ImagePlatform.of("linux/arm64/v1"); - given(http().head(eq(new URI(PING_URL)))) - .willReturn(responseWithHeaders(new BasicHeader(DockerApi.API_VERSION_HEADER_NAME, "1.41"))); - URI createUri = new URI(CONTAINERS_1_41_URL + "/create?platform=linux%2Farm64%2Fv1"); + if (apiVersion != null) { + given(http().head(eq(new URI(PING_URL)))) + .willReturn(responseWithHeaders(new BasicHeader(DockerApi.API_VERSION_HEADER_NAME, apiVersion))); + } + URI createUri = new URI(PLATFORM_CONTAINERS_URL + "/create?platform=linux%2Farm64%2Fv1"); given(http().post(eq(createUri), eq("application/json"), any())) .willReturn(responseOf("create-container-response.json")); ContainerReference containerReference = this.api.create(config, platform); @@ -600,11 +614,13 @@ void createWithPlatformCreatesContainer() throws Exception { } @Test - void createWithPlatformAndInsufficientApiVersionThrowsException() { + void createWithPlatformAndKnownInsufficientApiVersionThrowsException() throws Exception { ImageReference imageReference = ImageReference.of("ubuntu:bionic"); ContainerConfig config = ContainerConfig.of(imageReference, (update) -> update.withCommand("/bin/bash")); ImagePlatform platform = ImagePlatform.of("linux/arm64/v1"); - assertThatIllegalArgumentException().isThrownBy(() -> this.api.create(config, platform)) + given(http().head(eq(new URI(PING_URL)))) + .willReturn(responseWithHeaders(new BasicHeader(DockerApi.API_VERSION_HEADER_NAME, "1.24"))); + assertThatIllegalStateException().isThrownBy(() -> this.api.create(config, platform)) .withMessageContaining("must be at least 1.41") .withMessageContaining("current API version is 1.24"); } @@ -744,22 +760,22 @@ void getApiVersionWithVersionHeaderReturnsVersion() throws Exception { } @Test - void getApiVersionWithEmptyVersionHeaderReturnsDefaultVersion() throws Exception { + void getApiVersionWithEmptyVersionHeaderReturnsUnknownVersion() throws Exception { given(http().head(eq(new URI(PING_URL)))) .willReturn(responseWithHeaders(new BasicHeader(DockerApi.API_VERSION_HEADER_NAME, ""))); - assertThat(this.api.getApiVersion()).isEqualTo(DockerApi.MINIMUM_API_VERSION); + assertThat(this.api.getApiVersion()).isEqualTo(DockerApi.UNKNOWN_API_VERSION); } @Test - void getApiVersionWithNoVersionHeaderReturnsDefaultVersion() throws Exception { + void getApiVersionWithNoVersionHeaderReturnsUnknownVersion() throws Exception { given(http().head(eq(new URI(PING_URL)))).willReturn(emptyResponse()); - assertThat(this.api.getApiVersion()).isEqualTo(DockerApi.MINIMUM_API_VERSION); + assertThat(this.api.getApiVersion()).isEqualTo(DockerApi.UNKNOWN_API_VERSION); } @Test - void getApiVersionWithExceptionReturnsDefaultVersion() throws Exception { + void getApiVersionWithExceptionReturnsUnknownVersion() throws Exception { given(http().head(eq(new URI(PING_URL)))).willThrow(new IOException("simulated error")); - assertThat(this.api.getApiVersion()).isEqualTo(DockerApi.MINIMUM_API_VERSION); + assertThat(this.api.getApiVersion()).isEqualTo(DockerApi.UNKNOWN_API_VERSION); } } From 709b9bb149721652fd82a6c56fa049190d3bdd19 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 10 Dec 2024 13:19:53 -0800 Subject: [PATCH 128/203] Allow Jackson to escape new line chars when BOMR adds issues Remove the escaping logic when building the issue body so that Jackson can perform the actual escaping. Prior to this commit, the message body was double escaped. Closes gh-43479 --- .../springframework/boot/build/bom/bomr/MoveToSnapshots.java | 2 +- .../org/springframework/boot/build/bom/bomr/UpgradeBom.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/MoveToSnapshots.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/MoveToSnapshots.java index 2981277eb2d2..f04759873111 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/MoveToSnapshots.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/MoveToSnapshots.java @@ -93,7 +93,7 @@ protected String issueBody(Upgrade upgrade, Issue existingUpgrade) { if (existingUpgrade != null) { lines.add("Supersedes #" + existingUpgrade.getNumber()); } - return String.join("\\r\\n\\r\\n", lines); + return String.join("\n\n", lines); } @Override diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/UpgradeBom.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/UpgradeBom.java index 31db1352684a..b78628629d63 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/UpgradeBom.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/UpgradeBom.java @@ -88,7 +88,7 @@ protected String issueBody(Upgrade upgrade, Issue existingUpgrade) { if (existingUpgrade != null) { lines.add("Supersedes #" + existingUpgrade.getNumber()); } - return String.join("\\r\\n\\r\\n", lines); + return String.join("\n\n", lines); } } From e72546d2a629b6bbb6203724ad0536d254f0e8a9 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 10 Dec 2024 14:54:33 -0800 Subject: [PATCH 129/203] Add customizer variant of `requestFactorySettings` Add `requestFactorySettings` that accepts a `UnaryOperator` so that the existing `requestFactorySettings` can be customized rather than replaced. Closes gh-43258 --- .../boot/test/web/client/TestRestTemplate.java | 17 +++++++++++++++++ .../test/web/client/TestRestTemplateTests.java | 14 ++++++++++++-- .../boot/web/client/RestTemplateBuilder.java | 17 +++++++++++++++++ 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/web/client/TestRestTemplate.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/web/client/TestRestTemplate.java index 46c9067f8df3..c715b79fcd94 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/web/client/TestRestTemplate.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/web/client/TestRestTemplate.java @@ -25,6 +25,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.function.UnaryOperator; import javax.net.ssl.SSLContext; @@ -974,6 +975,22 @@ public TestRestTemplate withRequestFactorySettings(ClientHttpRequestFactorySetti this.restTemplate.getUriTemplateHandler()); } + /** + * Creates a new {@code TestRestTemplate} with the same configuration as this one, + * except that it will customize the {@link ClientHttpRequestFactorySettings}. The + * request factory used is a new instance of the underlying {@link RestTemplate}'s + * request factory type (when possible). + * @param requestFactorySettingsCustomizer a {@link UnaryOperator} to update the + * settings + * @return the new template + * @since 3.4.1 + */ + public TestRestTemplate withRequestFactorySettings( + UnaryOperator requestFactorySettingsCustomizer) { + return new TestRestTemplate(this.builder.requestFactorySettings(requestFactorySettingsCustomizer), + this.restTemplate.getUriTemplateHandler()); + } + @SuppressWarnings({ "rawtypes", "unchecked" }) private RequestEntity createRequestEntityWithRootAppliedUri(RequestEntity requestEntity) { return new RequestEntity(requestEntity.getBody(), requestEntity.getHeaders(), requestEntity.getMethod(), diff --git a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/web/client/TestRestTemplateTests.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/web/client/TestRestTemplateTests.java index dc99a59174a3..af69217f1f8e 100644 --- a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/web/client/TestRestTemplateTests.java +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/web/client/TestRestTemplateTests.java @@ -168,7 +168,7 @@ void httpComponentsAreBuildConsideringSettingsInRestTemplateBuilder() { } @Test - void withSettingsUpdatesRedirectsForHttpComponents() { + void withRequestFactorySettingsRedirectsForHttpComponents() { TestRestTemplate template = new TestRestTemplate(); assertThat(getRequestConfig(template).isRedirectsEnabled()).isFalse(); assertThat(getRequestConfig(template @@ -177,7 +177,7 @@ void withSettingsUpdatesRedirectsForHttpComponents() { } @Test - void withSettingsUpdatesRedirectsForJdk() { + void withRequestFactorySettingsRedirectsForJdk() { TestRestTemplate template = new TestRestTemplate( new RestTemplateBuilder().requestFactoryBuilder(ClientHttpRequestFactoryBuilder.jdk())); assertThat(getJdkHttpClient(template).followRedirects()).isEqualTo(Redirect.NORMAL); @@ -186,6 +186,16 @@ void withSettingsUpdatesRedirectsForJdk() { .followRedirects()).isEqualTo(Redirect.NEVER); } + @Test + void withRequestFactorySettingsUpdateRedirectsForJdk() { + TestRestTemplate template = new TestRestTemplate( + new RestTemplateBuilder().requestFactoryBuilder(ClientHttpRequestFactoryBuilder.jdk())); + assertThat(getJdkHttpClient(template).followRedirects()).isEqualTo(Redirect.NORMAL); + assertThat(getJdkHttpClient( + template.withRequestFactorySettings((settings) -> settings.withRedirects(Redirects.DONT_FOLLOW))) + .followRedirects()).isEqualTo(Redirect.NEVER); + } + private RequestConfig getRequestConfig(RestTemplateBuilder builder, HttpClientOption... httpClientOptions) { builder = (builder != null) ? builder : new RestTemplateBuilder(); TestRestTemplate template = new TestRestTemplate(builder, null, null, httpClientOptions); diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/RestTemplateBuilder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/RestTemplateBuilder.java index d8f574b506ef..5c9821e7dcf1 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/RestTemplateBuilder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/RestTemplateBuilder.java @@ -29,6 +29,7 @@ import java.util.Set; import java.util.function.Function; import java.util.function.Supplier; +import java.util.function.UnaryOperator; import org.springframework.beans.BeanUtils; import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder; @@ -451,6 +452,22 @@ public RestTemplateBuilder requestFactorySettings(ClientHttpRequestFactorySettin this.requestCustomizers); } + /** + * Update the {@link ClientHttpRequestFactorySettings} using the given customizer. + * @param requestFactorySettingsCustomizer a {@link UnaryOperator} to update request + * factory settings + * @return a new builder instance + * @since 3.4.1 + */ + public RestTemplateBuilder requestFactorySettings( + UnaryOperator requestFactorySettingsCustomizer) { + Assert.notNull(requestFactorySettingsCustomizer, "ClientHttpRequestFactorySettingsCustomizer must not be null"); + return new RestTemplateBuilder(requestFactorySettingsCustomizer.apply(this.requestFactorySettings), + this.detectRequestFactory, this.rootUri, this.messageConverters, this.interceptors, + this.requestFactoryBuilder, this.uriTemplateHandler, this.errorHandler, this.basicAuthentication, + this.defaultHeaders, this.customizers, this.requestCustomizers); + } + /** * Sets the connection timeout on the underlying {@link ClientHttpRequestFactory}. * @param connectTimeout the connection timeout From a964bbd8cb128575ecae1b38f901e356094dc23d Mon Sep 17 00:00:00 2001 From: Yanming Zhou Date: Wed, 11 Dec 2024 17:30:05 +0800 Subject: [PATCH 130/203] Polish variable name for consistency See gh-43483 --- .../boot/autoconfigure/h2/H2ConsoleAutoConfiguration.java | 4 ++-- 1 file changed, 2 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 7f2c096264f8..78d7395dae06 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 @@ -75,8 +75,8 @@ public ServletRegistrationBean h2Console() { } @Bean - H2ConsoleLogger h2ConsoleLogger(ObjectProvider dataSource) { - return new H2ConsoleLogger(dataSource, this.properties.getPath()); + H2ConsoleLogger h2ConsoleLogger(ObjectProvider dataSources) { + return new H2ConsoleLogger(dataSources, this.properties.getPath()); } private void configureH2ConsoleSettings(ServletRegistrationBean registration, From 42821f30bb35ece2d944177745c763af9e55083e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Wed, 11 Dec 2024 16:16:18 +0100 Subject: [PATCH 131/203] Start building against Spring Retry 2.0.11 snapshots See gh-43485 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 79445b7e30fc..1259c083c313 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2307,7 +2307,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-restdocs/releases/tag/v{version}") } } - library("Spring Retry", "2.0.10") { + library("Spring Retry", "2.0.11-SNAPSHOT") { considerSnapshots() group("org.springframework.retry") { modules = [ From e3b0fcf9b67d368bb4e0eaf6b4a67e3d12457220 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Wed, 11 Dec 2024 16:16:21 +0100 Subject: [PATCH 132/203] Start building against Spring Retry 2.0.11 snapshots See gh-43486 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index ec432a89ef88..2ba46f423ca1 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2290,7 +2290,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-restdocs/releases/tag/v{version}") } } - library("Spring Retry", "2.0.10") { + library("Spring Retry", "2.0.11-SNAPSHOT") { considerSnapshots() group("org.springframework.retry") { modules = [ From 22f527af6aeb02fdc244cdc931de4dc8147760db Mon Sep 17 00:00:00 2001 From: KIM MIN WOO <79193811+minwoo1999@users.noreply.github.com> Date: Sun, 8 Dec 2024 16:51:41 +0900 Subject: [PATCH 133/203] Add test for nullSafeValue with mapper transformation See gh-43441 --- .../jackson/JsonObjectDeserializerTests.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jackson/JsonObjectDeserializerTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jackson/JsonObjectDeserializerTests.java index 8461ce6ae8e7..57f505f7cf73 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jackson/JsonObjectDeserializerTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jackson/JsonObjectDeserializerTests.java @@ -19,6 +19,7 @@ import java.io.InputStream; import java.math.BigDecimal; import java.math.BigInteger; +import java.util.function.Function; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.ObjectCodec; @@ -144,6 +145,18 @@ void nullSafeValueWhenClassIsBigIntegerShouldReturnBigInteger() { assertThat(value).isEqualTo(BigInteger.TEN); } + @Test + void nullSafeValueWithMapperShouldTransformValue() { + JsonNode node = mock(JsonNode.class); + given(node.textValue()).willReturn("2023-12-01"); + + java.time.LocalDate result = this.testDeserializer.testNullSafeValue( + node, String.class, java.time.LocalDate::parse + ); + + assertThat(result).isEqualTo(java.time.LocalDate.of(2023, 12, 1)); + } + @Test void nullSafeValueWhenClassIsUnknownShouldThrowException() { assertThatIllegalArgumentException() @@ -189,6 +202,11 @@ protected T deserializeObject(JsonParser jsonParser, DeserializationContext cont return null; } + R testNullSafeValue(JsonNode jsonNode, Class type, Function mapper) { + return nullSafeValue(jsonNode, type, mapper); + } + + D testNullSafeValue(JsonNode jsonNode, Class type) { return nullSafeValue(jsonNode, type); } From d5d7152e5dcad80722e270fa998360f64dfabc62 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 11 Dec 2024 15:13:48 -0800 Subject: [PATCH 134/203] Polish 'Add test for nullSafeValue with mapper transformation' See gh-43441 --- .../boot/jackson/JsonObjectDeserializerTests.java | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jackson/JsonObjectDeserializerTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jackson/JsonObjectDeserializerTests.java index 57f505f7cf73..c0c23acb4755 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jackson/JsonObjectDeserializerTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jackson/JsonObjectDeserializerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -19,6 +19,7 @@ import java.io.InputStream; import java.math.BigDecimal; import java.math.BigInteger; +import java.time.LocalDate; import java.util.function.Function; import com.fasterxml.jackson.core.JsonParser; @@ -149,12 +150,8 @@ void nullSafeValueWhenClassIsBigIntegerShouldReturnBigInteger() { void nullSafeValueWithMapperShouldTransformValue() { JsonNode node = mock(JsonNode.class); given(node.textValue()).willReturn("2023-12-01"); - - java.time.LocalDate result = this.testDeserializer.testNullSafeValue( - node, String.class, java.time.LocalDate::parse - ); - - assertThat(result).isEqualTo(java.time.LocalDate.of(2023, 12, 1)); + LocalDate result = this.testDeserializer.testNullSafeValue(node, String.class, LocalDate::parse); + assertThat(result).isEqualTo(LocalDate.of(2023, 12, 1)); } @Test @@ -206,7 +203,6 @@ R testNullSafeValue(JsonNode jsonNode, Class type, Function mapp return nullSafeValue(jsonNode, type, mapper); } - D testNullSafeValue(JsonNode jsonNode, Class type) { return nullSafeValue(jsonNode, type); } From dc00342384521a5728c454a8ef02157b115e170f Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 4 Dec 2024 13:21:29 +0000 Subject: [PATCH 135/203] Improve handling of environment variables in failure analysis Prior to this change, the failure analysis for an invalid configuration property value filtered out the configuration property sources property source. This property source contains a "duplicate" of all of the environment's other property sources but with configuration property support (such as relaxed/fuzzy matching of environment variables). This was done to prevent the reporting of duplicates when a property was found in both the configuration property sources property source and the "normal" property sources. An unwanted side-effect of this was that fuzzy matching of environment variables was lost so the origin of com.example.some-property would be found in the environment variable was COM_EXAMPLE_SOME_PROPERTY but would not be found if it was COM_EXAMPLE_SOMEPROPERTY. This commit addresses this side-effect by no longer filtering out the configuration property sources property source. To then prevent duplicates from being reported in the analysis, it instead deduplicates things based on the origin of each property that's found in the environment's property sources. Fixes gh-43380 --- ...igurationPropertyValueFailureAnalyzer.java | 21 +++-- ...tionPropertyValueFailureAnalyzerTests.java | 83 ++++++++++++++++--- 2 files changed, 87 insertions(+), 17 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/InvalidConfigurationPropertyValueFailureAnalyzer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/InvalidConfigurationPropertyValueFailureAnalyzer.java index 9e2bd7a235d5..048024a44720 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/InvalidConfigurationPropertyValueFailureAnalyzer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/InvalidConfigurationPropertyValueFailureAnalyzer.java @@ -16,16 +16,18 @@ package org.springframework.boot.diagnostics.analyzer; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.stream.Stream; -import org.springframework.boot.context.properties.source.ConfigurationPropertySources; import org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException; import org.springframework.boot.diagnostics.AbstractFailureAnalyzer; import org.springframework.boot.diagnostics.FailureAnalysis; import org.springframework.boot.diagnostics.FailureAnalyzer; import org.springframework.boot.origin.Origin; import org.springframework.boot.origin.OriginLookup; +import org.springframework.boot.origin.PropertySourceOrigin; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.Environment; import org.springframework.core.env.PropertySource; @@ -61,18 +63,23 @@ protected FailureAnalysis analyze(Throwable rootFailure, InvalidConfigurationPro } private List getDescriptors(String propertyName) { + Set seen = new HashSet<>(); return getPropertySources().filter((source) -> source.containsProperty(propertyName)) .map((source) -> Descriptor.get(source, propertyName)) + .filter((descriptor) -> seen.add(getOrigin(descriptor))) .toList(); } - private Stream> getPropertySources() { - if (this.environment == null) { - return Stream.empty(); + private Origin getOrigin(Descriptor descriptor) { + Origin origin = descriptor.origin; + if (origin instanceof PropertySourceOrigin propertySourceOrigin) { + origin = propertySourceOrigin.getOrigin(); } - return this.environment.getPropertySources() - .stream() - .filter((source) -> !ConfigurationPropertySources.isAttachedConfigurationPropertySource(source)); + return origin; + } + + private Stream> getPropertySources() { + return (this.environment != null) ? this.environment.getPropertySources().stream() : Stream.empty(); } private void appendDetails(StringBuilder message, InvalidConfigurationPropertyValueException cause, diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/InvalidConfigurationPropertyValueFailureAnalyzerTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/InvalidConfigurationPropertyValueFailureAnalyzerTests.java index d50cd24c283b..df2b18b02da8 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/InvalidConfigurationPropertyValueFailureAnalyzerTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/InvalidConfigurationPropertyValueFailureAnalyzerTests.java @@ -20,13 +20,16 @@ import org.junit.jupiter.api.Test; +import org.springframework.boot.context.properties.source.ConfigurationPropertySources; import org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException; import org.springframework.boot.diagnostics.FailureAnalysis; import org.springframework.boot.origin.Origin; import org.springframework.boot.origin.OriginLookup; import org.springframework.core.env.EnumerablePropertySource; import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.SystemEnvironmentPropertySource; import org.springframework.mock.env.MockEnvironment; +import org.springframework.util.ObjectUtils; import static org.assertj.core.api.Assertions.assertThat; @@ -63,6 +66,26 @@ void analysisWithKnownProperty() { .doesNotContain("Additionally, this property is also set"); } + @Test + void analysisWithKnownPropertyFromSystemEnvironment() { + MapPropertySource source = new SystemEnvironmentPropertySource("systemEnvironment", + Collections.singletonMap("COM_EXAMPLE_TESTPROPERTY", "invalid")); + this.environment.getPropertySources().addFirst(source); + ConfigurationPropertySources.attach(this.environment); + assertThat(this.environment.getProperty("com.example.test-property")).isEqualTo("invalid"); + InvalidConfigurationPropertyValueException failure = new InvalidConfigurationPropertyValueException( + "com.example.test-property", "invalid", "This is not valid."); + FailureAnalysis analysis = performAnalysis(failure); + assertThat(analysis.getDescription()).contains("com.example.test-property") + .contains("invalid") + .contains("property source \"systemEnvironment\""); + assertThat(analysis.getCause()).isSameAs(failure); + assertThat(analysis.getAction()).contains("Review the value of the property with the provided reason."); + assertThat(analysis.getDescription()).contains("Validation failed for the following reason") + .contains("This is not valid.") + .doesNotContain("Additionally, this property is also set"); + } + @Test void analysisWithKnownPropertyAndNoReason() { MapPropertySource source = new MapPropertySource("test", Collections.singletonMap("test.property", "invalid")); @@ -84,6 +107,8 @@ void analysisWithKnownPropertyAndOtherCandidates() { this.environment.getPropertySources().addFirst(OriginCapablePropertySource.get(source)); this.environment.getPropertySources().addLast(additional); this.environment.getPropertySources().addLast(OriginCapablePropertySource.get(another)); + this.environment.getPropertySources().addLast(OriginCapablePropertySource.get("another-again", another)); + ConfigurationPropertySources.attach(this.environment); InvalidConfigurationPropertyValueException failure = new InvalidConfigurationPropertyValueException( "test.property", "invalid", "This is not valid."); FailureAnalysis analysis = performAnalysis(failure); @@ -92,7 +117,8 @@ void analysisWithKnownPropertyAndOtherCandidates() { assertThat(analysis.getDescription()) .contains("Additionally, this property is also set in the following property sources:") .contains("In 'additional' with the value 'valid'") - .contains("In 'another' with the value 'test' (originating from 'TestOrigin test.property')"); + .contains("In 'another' with the value 'test' (originating from 'TestOrigin test.property')") + .doesNotContain("another-again"); } @Test @@ -122,7 +148,11 @@ static class OriginCapablePropertySource extends EnumerablePropertySource private final EnumerablePropertySource propertySource; OriginCapablePropertySource(EnumerablePropertySource propertySource) { - super(propertySource.getName(), propertySource.getSource()); + this(propertySource.getName(), propertySource); + } + + OriginCapablePropertySource(String name, EnumerablePropertySource propertySource) { + super(name, propertySource.getSource()); this.propertySource = propertySource; } @@ -138,20 +168,53 @@ public String[] getPropertyNames() { @Override public Origin getOrigin(String name) { - return new Origin() { - - @Override - public String toString() { - return "TestOrigin " + name; - } - - }; + return new TestOrigin(name, this.propertySource.getName()); } static OriginCapablePropertySource get(EnumerablePropertySource propertySource) { return new OriginCapablePropertySource<>(propertySource); } + static OriginCapablePropertySource get(String name, EnumerablePropertySource propertySource) { + return new OriginCapablePropertySource<>(name, propertySource); + } + + static final class TestOrigin implements Origin { + + private final String name; + + private final String sourceName; + + private TestOrigin(String name, String sourceName) { + this.name = name; + this.sourceName = sourceName; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + TestOrigin other = (TestOrigin) obj; + return ObjectUtils.nullSafeEquals(this.name, other.name) + && ObjectUtils.nullSafeEquals(this.sourceName, other.sourceName); + } + + @Override + public int hashCode() { + return ObjectUtils.nullSafeHashCode(this.name); + } + + @Override + public String toString() { + return "TestOrigin " + this.name; + } + + } + } } From 64015df798303b631c0a9e1cb6cece621b3d37d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Thu, 12 Dec 2024 11:29:42 +0100 Subject: [PATCH 136/203] Upgrade to Jetty 12.0.16 Closes gh-43487 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 1259c083c313..d6d2dffcdd65 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -970,7 +970,7 @@ bom { ] } } - library("Jetty", "12.0.15") { + library("Jetty", "12.0.16") { group("org.eclipse.jetty.ee10") { imports = [ "jetty-ee10-bom" From 98f2b239d9e8e0c9499068a5a151ce1494885c1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Thu, 12 Dec 2024 11:29:42 +0100 Subject: [PATCH 137/203] Upgrade to Spring Framework 6.1.16 Closes gh-43393 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 682b2e319dcc..1006a5e0eaf1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -19,7 +19,7 @@ mavenVersion=3.9.4 mockitoVersion=5.11.0 nativeBuildToolsVersion=0.10.4 snakeYamlVersion=2.2 -springFrameworkVersion=6.1.16-SNAPSHOT +springFrameworkVersion=6.1.16 springFramework60xVersion=6.0.23 tomcatVersion=10.1.34 From 92e241798e700d058529bc3ccd2eb76206c66ef5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Thu, 12 Dec 2024 11:29:43 +0100 Subject: [PATCH 138/203] Upgrade to Spring HATEOAS 2.3.4 Closes gh-43475 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index d6d2dffcdd65..83e01608a1b5 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2201,7 +2201,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-graphql/releases/tag/v{version}") } } - library("Spring HATEOAS", "2.3.4-SNAPSHOT") { + library("Spring HATEOAS", "2.3.4") { considerSnapshots() group("org.springframework.hateoas") { modules = [ From de18f0ed43b703ba043f93ff995ae6f3e0f8053f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Thu, 12 Dec 2024 11:34:20 +0100 Subject: [PATCH 139/203] Upgrade to Jetty 12.0.16 Closes gh-43488 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 2ba46f423ca1..7c42489b450c 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -987,7 +987,7 @@ bom { ] } } - library("Jetty", "12.0.15") { + library("Jetty", "12.0.16") { group("org.eclipse.jetty.ee10") { imports = [ "jetty-ee10-bom" From f32600a48f3a3a68e7c95a2b9d20bd86e61b631f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Thu, 12 Dec 2024 11:34:20 +0100 Subject: [PATCH 140/203] Upgrade to Spring Framework 6.2.1 Closes gh-43414 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 511346aad001..2ab7e8948c3d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -19,7 +19,7 @@ mavenVersion=3.9.4 mockitoVersion=5.14.2 nativeBuildToolsVersion=0.10.4 snakeYamlVersion=2.3 -springFrameworkVersion=6.2.1-SNAPSHOT +springFrameworkVersion=6.2.1 springFramework60xVersion=6.0.23 tomcatVersion=10.1.34 From 20fc18458e225eae8d911951f5fbddb21f029389 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Thu, 12 Dec 2024 11:34:21 +0100 Subject: [PATCH 141/203] Upgrade to Spring HATEOAS 2.4.1 Closes gh-43478 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 7c42489b450c..dec5aeced554 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2184,7 +2184,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-graphql/releases/tag/v{version}") } } - library("Spring HATEOAS", "2.4.1-SNAPSHOT") { + library("Spring HATEOAS", "2.4.1") { considerSnapshots() group("org.springframework.hateoas") { modules = [ From 8572d9e177ce67d108210e318f97f13512630458 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 12 Dec 2024 11:05:58 +0000 Subject: [PATCH 142/203] Restore previous Main-Class configuration This partially reverts commit d924e4d9998945933a4a9947a6ca776e303db1ea. See gh-43284 --- .../spring-boot-starter-parent/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-parent/build.gradle b/spring-boot-project/spring-boot-starters/spring-boot-starter-parent/build.gradle index 6c4c81d4c4f0..490d57310f35 100644 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-parent/build.gradle +++ b/spring-boot-project/spring-boot-starters/spring-boot-starter-parent/build.gradle @@ -234,8 +234,8 @@ publishing.publications.withType(MavenPublication) { } transformer(implementation: 'org.apache.maven.plugins.shade.resource.ServicesResourceTransformer') transformer(implementation: 'org.apache.maven.plugins.shade.resource.ManifestResourceTransformer') { + delegate.mainClass('${start-class}') manifestEntries { - delegate.'Main-Class'('${start-class}') delegate.'Multi-Release'('true') } } From ccc1b5da2864905d9cbf1ce465c02aec3a37c4f3 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Thu, 12 Dec 2024 15:17:02 -0800 Subject: [PATCH 143/203] Don't call `Startable.start()` for already started containers Add a new `TestcontainersStartup.start` static method and update the existing start methods so that `Startable.start()` is only called when the container is not already running. Prior to this commit, we assumed that `Startable.start()` calls were idempotent and could be safely made multiple times. Whilst this appears to be true for stock `GenericContainer` based startables, users may have their own `start()` method that does not expect to be called multiple times. The implemented detection logic will not be applied if a `Startable` is not also a `Container`. In these cases, the implementation will need to deal directly with multiple `start()` calls. Fixed gh-43253 --- ...onStartsConnectionOnceIntegrationTest.java | 76 +++++++++++++ ...tcontainersLifecycleBeanPostProcessor.java | 2 +- .../lifecycle/TestcontainersStartup.java | 78 +++++++++++++- .../ContainerConnectionDetailsFactory.java | 3 +- .../lifecycle/TestcontainersStartupTests.java | 101 +++++++++++++++++- 5 files changed, 253 insertions(+), 7 deletions(-) create mode 100644 spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/service/connection/ServiceConnectionStartsConnectionOnceIntegrationTest.java diff --git a/spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/service/connection/ServiceConnectionStartsConnectionOnceIntegrationTest.java b/spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/service/connection/ServiceConnectionStartsConnectionOnceIntegrationTest.java new file mode 100644 index 000000000000..45f96e98b915 --- /dev/null +++ b/spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/service/connection/ServiceConnectionStartsConnectionOnceIntegrationTest.java @@ -0,0 +1,76 @@ +/* + * Copyright 2012-2024 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.testcontainers.service.connection; + +import java.util.concurrent.atomic.AtomicInteger; + +import org.junit.jupiter.api.Test; +import org.testcontainers.containers.PostgreSQLContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; + +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.testsupport.container.TestImage; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Integration tests to ensure containers are started only once. + * + * @author Phillip Webb + */ +@SpringJUnitConfig +@Testcontainers(disabledWithoutDocker = true) +class ServiceConnectionStartsConnectionOnceIntegrationTest { + + @Container + @ServiceConnection + static final StartCountingPostgreSQLContainer postgres = TestImage + .container(StartCountingPostgreSQLContainer.class); + + @Test + void startedOnlyOnce() { + assertThat(postgres.startCount.get()).isOne(); + } + + @Configuration(proxyBeanMethods = false) + @ImportAutoConfiguration(DataSourceAutoConfiguration.class) + static class TestConfiguration { + + } + + static class StartCountingPostgreSQLContainer extends PostgreSQLContainer { + + final AtomicInteger startCount = new AtomicInteger(); + + StartCountingPostgreSQLContainer(DockerImageName dockerImageName) { + super(dockerImageName); + } + + @Override + public void start() { + this.startCount.incrementAndGet(); + super.start(); + } + + } + +} diff --git a/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/lifecycle/TestcontainersLifecycleBeanPostProcessor.java b/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/lifecycle/TestcontainersLifecycleBeanPostProcessor.java index f1754048e98a..a09d7906c99e 100644 --- a/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/lifecycle/TestcontainersLifecycleBeanPostProcessor.java +++ b/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/lifecycle/TestcontainersLifecycleBeanPostProcessor.java @@ -97,7 +97,7 @@ public Object postProcessAfterInitialization(Object bean, String beanName) throw } else if (this.startables.get() == Startables.STARTED) { logger.trace(LogMessage.format("Starting container %s", beanName)); - startableBean.start(); + TestcontainersStartup.start(startableBean); } } return bean; diff --git a/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/lifecycle/TestcontainersStartup.java b/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/lifecycle/TestcontainersStartup.java index 00009a07fa6c..9a44bf3aa858 100644 --- a/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/lifecycle/TestcontainersStartup.java +++ b/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/lifecycle/TestcontainersStartup.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -17,7 +17,13 @@ package org.springframework.boot.testcontainers.lifecycle; import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import org.testcontainers.containers.Container; import org.testcontainers.lifecycle.Startable; import org.testcontainers.lifecycle.Startables; @@ -40,7 +46,7 @@ public enum TestcontainersStartup { @Override void start(Collection startables) { - startables.forEach(Startable::start); + startables.forEach(TestcontainersStartup::start); } }, @@ -52,7 +58,8 @@ void start(Collection startables) { @Override void start(Collection startables) { - Startables.deepStart(startables).join(); + SingleStartables singleStartables = new SingleStartables(); + Startables.deepStart(startables.stream().map(singleStartables::getOrCreate)).join(); } }; @@ -91,4 +98,69 @@ private static String getCanonicalName(String name) { return canonicalName.toString(); } + /** + * Start the given {@link Startable} unless is's detected as already running. + * @param startable the startable to start + * @since 3.4.1 + */ + public static void start(Startable startable) { + if (!isRunning(startable)) { + startable.start(); + } + } + + private static boolean isRunning(Startable startable) { + try { + return (startable instanceof Container container) && container.isRunning(); + } + catch (Throwable ex) { + return false; + + } + } + + /** + * Tracks and adapts {@link Startable} instances to use + * {@link TestcontainersStartup#start(Startable)} so containers are only started once + * even when calling {@link Startables#deepStart(java.util.stream.Stream)}. + */ + private static final class SingleStartables { + + private final Map adapters = new HashMap<>(); + + SingleStartable getOrCreate(Startable startable) { + return this.adapters.computeIfAbsent(startable, this::create); + } + + private SingleStartable create(Startable startable) { + return new SingleStartable(this, startable); + } + + record SingleStartable(SingleStartables singleStartables, Startable startable) implements Startable { + + @Override + public Set getDependencies() { + Set dependencies = this.startable.getDependencies(); + if (dependencies.isEmpty()) { + return dependencies; + } + return dependencies.stream() + .map(this.singleStartables::getOrCreate) + .collect(Collectors.toCollection(LinkedHashSet::new)); + } + + @Override + public void start() { + TestcontainersStartup.start(this.startable); + } + + @Override + public void stop() { + this.startable.stop(); + } + + } + + } + } diff --git a/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/ContainerConnectionDetailsFactory.java b/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/ContainerConnectionDetailsFactory.java index af6e6f916e7b..14518b982d8b 100644 --- a/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/ContainerConnectionDetailsFactory.java +++ b/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/ContainerConnectionDetailsFactory.java @@ -33,6 +33,7 @@ import org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory; import org.springframework.boot.origin.Origin; import org.springframework.boot.origin.OriginProvider; +import org.springframework.boot.testcontainers.lifecycle.TestcontainersStartup; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.core.ResolvableType; @@ -188,7 +189,7 @@ protected final C getContainer() { Assert.state(this.container != null, "Container cannot be obtained before the connection details bean has been initialized"); if (this.container instanceof Startable startable) { - startable.start(); + TestcontainersStartup.start(startable); } return this.container; } diff --git a/spring-boot-project/spring-boot-testcontainers/src/test/java/org/springframework/boot/testcontainers/lifecycle/TestcontainersStartupTests.java b/spring-boot-project/spring-boot-testcontainers/src/test/java/org/springframework/boot/testcontainers/lifecycle/TestcontainersStartupTests.java index b50e6ef63a58..38c3857b970d 100644 --- a/spring-boot-project/spring-boot-testcontainers/src/test/java/org/springframework/boot/testcontainers/lifecycle/TestcontainersStartupTests.java +++ b/spring-boot-project/spring-boot-testcontainers/src/test/java/org/springframework/boot/testcontainers/lifecycle/TestcontainersStartupTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -17,10 +17,13 @@ package org.springframework.boot.testcontainers.lifecycle; import java.util.ArrayList; +import java.util.Collection; import java.util.List; +import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import org.junit.jupiter.api.Test; +import org.testcontainers.containers.GenericContainer; import org.testcontainers.lifecycle.Startable; import org.springframework.mock.env.MockEnvironment; @@ -39,6 +42,16 @@ class TestcontainersStartupTests { private final AtomicInteger counter = new AtomicInteger(); + @Test + void startSingleStartsOnlyOnce() { + TestStartable startable = new TestStartable(); + assertThat(startable.startCount).isZero(); + TestcontainersStartup.start(startable); + assertThat(startable.startCount).isOne(); + TestcontainersStartup.start(startable); + assertThat(startable.startCount).isOne(); + } + @Test void startWhenSquentialStartsSequentially() { List startables = createTestStartables(100); @@ -49,6 +62,22 @@ void startWhenSquentialStartsSequentially() { } } + @Test + void startWhenSquentialStartsOnlyOnce() { + List startables = createTestStartables(10); + for (int i = 0; i < startables.size(); i++) { + assertThat(startables.get(i).getStartCount()).isZero(); + } + TestcontainersStartup.SEQUENTIAL.start(startables); + for (int i = 0; i < startables.size(); i++) { + assertThat(startables.get(i).getStartCount()).isOne(); + } + TestcontainersStartup.SEQUENTIAL.start(startables); + for (int i = 0; i < startables.size(); i++) { + assertThat(startables.get(i).getStartCount()).isOne(); + } + } + @Test void startWhenParallelStartsInParallel() { List startables = createTestStartables(100); @@ -56,6 +85,47 @@ void startWhenParallelStartsInParallel() { assertThat(startables.stream().map(TestStartable::getThreadName)).hasSizeGreaterThan(1); } + @Test + void startWhenParallelStartsOnlyOnce() { + List startables = createTestStartables(10); + for (int i = 0; i < startables.size(); i++) { + assertThat(startables.get(i).getStartCount()).isZero(); + } + TestcontainersStartup.PARALLEL.start(startables); + for (int i = 0; i < startables.size(); i++) { + assertThat(startables.get(i).getStartCount()).isOne(); + } + TestcontainersStartup.PARALLEL.start(startables); + for (int i = 0; i < startables.size(); i++) { + assertThat(startables.get(i).getStartCount()).isOne(); + } + } + + @Test + void startWhenParallelStartsDependenciesOnlyOnce() { + List dependencies = createTestStartables(10); + TestStartable first = new TestStartable(dependencies); + TestStartable second = new TestStartable(dependencies); + List startables = List.of(first, second); + assertThat(first.getStartCount()).isZero(); + assertThat(second.getStartCount()).isZero(); + for (int i = 0; i < startables.size(); i++) { + assertThat(dependencies.get(i).getStartCount()).isZero(); + } + TestcontainersStartup.PARALLEL.start(startables); + assertThat(first.getStartCount()).isOne(); + assertThat(second.getStartCount()).isOne(); + for (int i = 0; i < startables.size(); i++) { + assertThat(dependencies.get(i).getStartCount()).isOne(); + } + TestcontainersStartup.PARALLEL.start(startables); + assertThat(first.getStartCount()).isOne(); + assertThat(second.getStartCount()).isOne(); + for (int i = 0; i < startables.size(); i++) { + assertThat(dependencies.get(i).getStartCount()).isOne(); + } + } + @Test void getWhenNoPropertyReturnsDefault() { MockEnvironment environment = new MockEnvironment(); @@ -93,20 +163,43 @@ private List createTestStartables(int size) { return testStartables; } - private final class TestStartable implements Startable { + private class TestStartable extends GenericContainer { + + private int startCount; private int index; private String threadName; + TestStartable() { + super("test"); + } + + TestStartable(Collection startables) { + super("test"); + this.dependencies.addAll(startables); + } + + @Override + public Set getDependencies() { + return this.dependencies; + } + @Override public void start() { + this.startCount++; this.index = TestcontainersStartupTests.this.counter.getAndIncrement(); this.threadName = Thread.currentThread().getName(); } @Override public void stop() { + this.startCount--; + } + + @Override + public boolean isRunning() { + return this.startCount > 0; } int getIndex() { @@ -117,6 +210,10 @@ String getThreadName() { return this.threadName; } + int getStartCount() { + return this.startCount; + } + } } From 1234409fbe8e6d9d41460effb4ec66cf061ce112 Mon Sep 17 00:00:00 2001 From: Dmytro Nosan Date: Fri, 13 Dec 2024 11:30:47 +0200 Subject: [PATCH 144/203] Multiple WebFlux ResourceHandlerRegistrationCustomizer should be invoked Before this commit, only a single ResourceHandlerRegistrationCustomizer was invoked. This commit adds functionality to have more than one ResourceHandlerRegistrationCustomizers See gh-43494 --- .../reactive/WebFluxAutoConfiguration.java | 20 ++++++------- .../WebFluxAutoConfigurationTests.java | 29 +++++++++++++++++++ 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java index be7e3e3dda4e..96218e0fe3d9 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java @@ -17,6 +17,7 @@ package org.springframework.boot.autoconfigure.web.reactive; import java.time.Duration; +import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -163,14 +164,14 @@ public static class WebFluxConfig implements WebFluxConfigurer { private final ObjectProvider codecCustomizers; - private final ResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer; + private final ObjectProvider resourceHandlerRegistrationCustomizers; private final ObjectProvider viewResolvers; public WebFluxConfig(Environment environment, WebProperties webProperties, WebFluxProperties webFluxProperties, ListableBeanFactory beanFactory, ObjectProvider resolvers, ObjectProvider codecCustomizers, - ObjectProvider resourceHandlerRegistrationCustomizer, + ObjectProvider resourceHandlerRegistrationCustomizers, ObjectProvider viewResolvers) { this.environment = environment; this.resourceProperties = webProperties.getResources(); @@ -178,7 +179,7 @@ public WebFluxConfig(Environment environment, WebProperties webProperties, WebFl this.beanFactory = beanFactory; this.argumentResolvers = resolvers; this.codecCustomizers = codecCustomizers; - this.resourceHandlerRegistrationCustomizer = resourceHandlerRegistrationCustomizer.getIfAvailable(); + this.resourceHandlerRegistrationCustomizers = resourceHandlerRegistrationCustomizers; this.viewResolvers = viewResolvers; } @@ -210,19 +211,22 @@ public void addResourceHandlers(ResourceHandlerRegistry registry) { logger.debug("Default resource handling disabled"); return; } + List resourceHandlerRegistrationCustomizers = this.resourceHandlerRegistrationCustomizers + .orderedStream() + .toList(); String webjarsPathPattern = this.webFluxProperties.getWebjarsPathPattern(); if (!registry.hasMappingForPattern(webjarsPathPattern)) { ResourceHandlerRegistration registration = registry.addResourceHandler(webjarsPathPattern) .addResourceLocations("classpath:/META-INF/resources/webjars/"); configureResourceCaching(registration); - customizeResourceHandlerRegistration(registration); + resourceHandlerRegistrationCustomizers.forEach((customizer) -> customizer.customize(registration)); } String staticPathPattern = this.webFluxProperties.getStaticPathPattern(); if (!registry.hasMappingForPattern(staticPathPattern)) { ResourceHandlerRegistration registration = registry.addResourceHandler(staticPathPattern) .addResourceLocations(this.resourceProperties.getStaticLocations()); configureResourceCaching(registration); - customizeResourceHandlerRegistration(registration); + resourceHandlerRegistrationCustomizers.forEach((customizer) -> customizer.customize(registration)); } } @@ -247,12 +251,6 @@ public void addFormatters(FormatterRegistry registry) { ApplicationConversionService.addBeans(registry, this.beanFactory); } - private void customizeResourceHandlerRegistration(ResourceHandlerRegistration registration) { - if (this.resourceHandlerRegistrationCustomizer != null) { - this.resourceHandlerRegistrationCustomizer.customize(registration); - } - } - } /** diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfigurationTests.java index 27ae96ee440e..d6127133dcc7 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfigurationTests.java @@ -90,6 +90,7 @@ import org.springframework.web.reactive.accept.RequestedContentTypeResolver; import org.springframework.web.reactive.config.BlockingExecutionConfigurer; import org.springframework.web.reactive.config.DelegatingWebFluxConfiguration; +import org.springframework.web.reactive.config.ResourceHandlerRegistration; import org.springframework.web.reactive.config.WebFluxConfigurationSupport; import org.springframework.web.reactive.config.WebFluxConfigurer; import org.springframework.web.reactive.function.server.support.RouterFunctionMapping; @@ -122,6 +123,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.then; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; /** * Tests for {@link WebFluxAutoConfiguration}. @@ -182,6 +184,18 @@ void shouldCustomizeCodecs() { }); } + @Test + void shouldCustomizeResources() { + this.contextRunner.withUserConfiguration(ResourceHandlerRegistrationCustomizers.class).run((context) -> { + ResourceHandlerRegistrationCustomizer customizer1 = context + .getBean("firstResourceHandlerRegistrationCustomizer", ResourceHandlerRegistrationCustomizer.class); + ResourceHandlerRegistrationCustomizer customizer2 = context + .getBean("secondResourceHandlerRegistrationCustomizer", ResourceHandlerRegistrationCustomizer.class); + then(customizer1).should(times(2)).customize(any(ResourceHandlerRegistration.class)); + then(customizer2).should(times(2)).customize(any(ResourceHandlerRegistration.class)); + }); + } + @Test void shouldRegisterResourceHandlerMapping() { this.contextRunner.run((context) -> { @@ -843,6 +857,21 @@ CodecCustomizer firstCodecCustomizer() { } + @Configuration(proxyBeanMethods = false) + static class ResourceHandlerRegistrationCustomizers { + + @Bean + ResourceHandlerRegistrationCustomizer firstResourceHandlerRegistrationCustomizer() { + return mock(ResourceHandlerRegistrationCustomizer.class); + } + + @Bean + ResourceHandlerRegistrationCustomizer secondResourceHandlerRegistrationCustomizer() { + return mock(ResourceHandlerRegistrationCustomizer.class); + } + + } + @Configuration(proxyBeanMethods = false) static class ViewResolvers { From 4a520714e5277d153c07f896f9e60dabd77c243d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Fri, 13 Dec 2024 16:43:13 +0100 Subject: [PATCH 145/203] Upgrade to Couchbase Client 3.7.6 Closes gh-43500 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index dec5aeced554..cba3ff81bc78 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -254,7 +254,7 @@ bom { site("https://commons.apache.org/proper/commons-pool") } } - library("Couchbase Client", "3.7.5") { + library("Couchbase Client", "3.7.6") { group("com.couchbase.client") { modules = [ "java-client" From 3792a8ab2b912ff368f591b4499cc5b744b7c059 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Fri, 13 Dec 2024 16:43:18 +0100 Subject: [PATCH 146/203] Upgrade to Log4j2 2.24.3 Closes gh-43501 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index cba3ff81bc78..351c17728a85 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -1219,7 +1219,7 @@ bom { releaseNotes("https://github.com/liquibase/liquibase/releases/tag/v{version}") } } - library("Log4j2", "2.24.2") { + library("Log4j2", "2.24.3") { group("org.apache.logging.log4j") { imports = [ "log4j-bom" From b283e1d915e33fcfa6958f5c5d54ff691f520097 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Fri, 13 Dec 2024 16:43:21 +0100 Subject: [PATCH 147/203] Upgrade to Kafka 3.7.2 Closes gh-43502 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 83e01608a1b5..43a0461ec6bd 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -1078,7 +1078,7 @@ bom { releaseNotes("https://junit.org/junit5/docs/{version}/release-notes") } } - library("Kafka", "3.7.1") { + library("Kafka", "3.7.2") { group("org.apache.kafka") { modules = [ "connect", From 487d8d58224073fe88d5156e1e3ca38a9f88f632 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Fri, 13 Dec 2024 16:43:22 +0100 Subject: [PATCH 148/203] Upgrade to Spring Data Bom 2024.0.7 Closes gh-43392 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 43a0461ec6bd..14630a811d5f 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2149,7 +2149,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-batch/releases/tag/v{version}") } } - library("Spring Data Bom", "2024.0.7-SNAPSHOT") { + library("Spring Data Bom", "2024.0.7") { considerSnapshots() calendarName = "Spring Data Release" group("org.springframework.data") { From 4d32fb09ee8c5be46b063562d8cabca113e9a5f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Fri, 13 Dec 2024 16:43:22 +0100 Subject: [PATCH 149/203] Upgrade to Spring LDAP 3.2.10 Closes gh-43395 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 14630a811d5f..95f6c60d25d9 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2253,7 +2253,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-kafka/releases/tag/v{version}") } } - library("Spring LDAP", "3.2.9-SNAPSHOT") { + library("Spring LDAP", "3.2.10") { considerSnapshots() group("org.springframework.ldap") { modules = [ From 42aff42d7174c4dff9b037169f90d1575924beeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Fri, 13 Dec 2024 16:43:24 +0100 Subject: [PATCH 150/203] Upgrade to Prometheus Client 1.3.5 Closes gh-43503 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 351c17728a85..91de6501f72d 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -1678,7 +1678,7 @@ bom { releaseNotes("https://github.com/pgjdbc/pgjdbc/releases/tag/REL{version}") } } - library("Prometheus Client", "1.3.4") { + library("Prometheus Client", "1.3.5") { group("io.prometheus") { imports = [ "prometheus-metrics-bom" From 236fa617e6f9a10e3ffc623c54c3734feb717ca2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Fri, 13 Dec 2024 16:43:24 +0100 Subject: [PATCH 151/203] Upgrade to Spring Data Bom 2024.1.1 Closes gh-43413 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 91de6501f72d..7ed2200bc24b 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2132,7 +2132,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-batch/releases/tag/v{version}") } } - library("Spring Data Bom", "2024.1.1-SNAPSHOT") { + library("Spring Data Bom", "2024.1.1") { considerSnapshots() calendarName = "Spring Data Release" group("org.springframework.data") { From dd1e09ea16799c1ed4ca182a0b3ca34f252da918 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Fri, 13 Dec 2024 16:43:24 +0100 Subject: [PATCH 152/203] Upgrade to Spring LDAP 3.2.10 Closes gh-43417 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 7ed2200bc24b..fec1086c7c95 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2236,7 +2236,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-kafka/releases/tag/v{version}") } } - library("Spring LDAP", "3.2.9-SNAPSHOT") { + library("Spring LDAP", "3.2.10") { considerSnapshots() group("org.springframework.ldap") { modules = [ From 4d15ee5bf09dcf08cd7969de773e77b98f782fd3 Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Fri, 13 Dec 2024 23:40:38 +0900 Subject: [PATCH 153/203] Polish See gh-43498 --- CONTRIBUTING.adoc | 2 +- .../boot/build/bom/CheckBom.java | 2 +- .../OnEnabledLoggingExportCondition.java | 5 +- .../test/resources/batch/custom-schema.sql | 66 +++++++++---------- .../reference/pages/io/rest-client.adoc | 4 +- .../MyClientHttpConfiguration.kt | 2 +- .../json/app/ExampleJsonComponent.java | 2 +- .../json/JSONObject.java | 2 +- .../boot/util/Instantiator.java | 6 +- .../boot/web/client/RestTemplateBuilder.java | 2 +- ...PortInfoApplicationContextInitializer.java | 4 +- ...verContainerInvocationContextProvider.java | 5 +- 12 files changed, 52 insertions(+), 50 deletions(-) diff --git a/CONTRIBUTING.adoc b/CONTRIBUTING.adoc index 6e09addf884c..a8ff958ac9ff 100755 --- a/CONTRIBUTING.adoc +++ b/CONTRIBUTING.adoc @@ -43,7 +43,7 @@ None of these is essential for a pull request, but they will all help. They can added after the original pull request but before a merge. * We use the https://github.com/spring-io/spring-javaformat/[Spring JavaFormat] project to apply code formatting conventions. - If you use Eclipse and you follow the https://github.com/spring-projects/spring-boot/wiki/Working-with-the-Code#importing-into-eclipse["Importing into eclipse"] instructions you should get project specific formatting automatically. + If you use Eclipse and you follow the https://github.com/spring-projects/spring-boot/wiki/Working-with-the-Code#importing-into-eclipse["Importing into Eclipse"] instructions you should get project-specific formatting automatically. You can also install the https://github.com/spring-io/spring-javaformat/#intellij-idea[Spring JavaFormat IntelliJ Plugin] or format the code from the Gradle build by running `./gradlew format`. Note that if you have format violations in `buildSrc`, you can fix them by running `./gradlew -p buildSrc format` from the project root directory. * The build includes Checkstyle rules for many of our code conventions. Run `./gradlew checkstyleMain checkstyleTest` if you want to check your changes are compliant. diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/CheckBom.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/CheckBom.java index 250aa5d559ef..365e67c6784c 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/bom/CheckBom.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/CheckBom.java @@ -216,7 +216,7 @@ private File resolveBom(Library library, String alignsWithBom) { .getResolvedConfiguration() .getResolvedArtifacts(); if (artifacts.size() != 1) { - throw new IllegalStateException("Expected a single file but '%s' resolved to %d artifacts" + throw new IllegalStateException("Expected a single artifact but '%s' resolved to %d artifacts" .formatted(coordinates, artifacts.size())); } return artifacts.iterator().next().getFile(); diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/OnEnabledLoggingExportCondition.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/OnEnabledLoggingExportCondition.java index eb328c816525..dbd22e9efe78 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/OnEnabledLoggingExportCondition.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/OnEnabledLoggingExportCondition.java @@ -42,12 +42,13 @@ class OnEnabledLoggingExportCondition extends SpringBootCondition { public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { String loggingExporter = getExporterName(metadata); if (StringUtils.hasLength(loggingExporter)) { + String formattedExporterProperty = EXPORTER_PROPERTY.formatted(loggingExporter); Boolean exporterLoggingEnabled = context.getEnvironment() - .getProperty(EXPORTER_PROPERTY.formatted(loggingExporter), Boolean.class); + .getProperty(formattedExporterProperty, Boolean.class); if (exporterLoggingEnabled != null) { return new ConditionOutcome(exporterLoggingEnabled, ConditionMessage.forCondition(ConditionalOnEnabledLoggingExport.class) - .because(EXPORTER_PROPERTY.formatted(loggingExporter) + " is " + exporterLoggingEnabled)); + .because(formattedExporterProperty + " is " + exporterLoggingEnabled)); } } Boolean globalLoggingEnabled = context.getEnvironment().getProperty(GLOBAL_PROPERTY, Boolean.class); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/resources/batch/custom-schema.sql b/spring-boot-project/spring-boot-autoconfigure/src/test/resources/batch/custom-schema.sql index 5953b5c47959..2181b1132579 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/resources/batch/custom-schema.sql +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/resources/batch/custom-schema.sql @@ -1,21 +1,21 @@ CREATE TABLE PREFIX_JOB_INSTANCE ( - JOB_INSTANCE_ID BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY , - VERSION BIGINT , + JOB_INSTANCE_ID BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + VERSION BIGINT, JOB_NAME VARCHAR(100) NOT NULL, JOB_KEY VARCHAR(32) NOT NULL, constraint JOB_INST_UN unique (JOB_NAME, JOB_KEY) ) ; CREATE TABLE PREFIX_JOB_EXECUTION ( - JOB_EXECUTION_ID BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY , - VERSION BIGINT , + JOB_EXECUTION_ID BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + VERSION BIGINT, JOB_INSTANCE_ID BIGINT NOT NULL, CREATE_TIME TIMESTAMP NOT NULL, - START_TIME TIMESTAMP DEFAULT NULL , - END_TIME TIMESTAMP DEFAULT NULL , - STATUS VARCHAR(10) , - EXIT_CODE VARCHAR(2500) , - EXIT_MESSAGE VARCHAR(2500) , + START_TIME TIMESTAMP DEFAULT NULL, + END_TIME TIMESTAMP DEFAULT NULL, + STATUS VARCHAR(10), + EXIT_CODE VARCHAR(2500), + EXIT_MESSAGE VARCHAR(2500), LAST_UPDATED TIMESTAMP, JOB_CONFIGURATION_LOCATION VARCHAR(2500) NULL, constraint JOB_INST_EXEC_FK foreign key (JOB_INSTANCE_ID) @@ -23,36 +23,36 @@ CREATE TABLE PREFIX_JOB_EXECUTION ( ) ; CREATE TABLE PREFIX_JOB_EXECUTION_PARAMS ( - JOB_EXECUTION_ID BIGINT NOT NULL , - TYPE_CD VARCHAR(6) NOT NULL , - KEY_NAME VARCHAR(100) NOT NULL , - STRING_VAL VARCHAR(250) , - DATE_VAL TIMESTAMP DEFAULT NULL , - LONG_VAL BIGINT , - DOUBLE_VAL DOUBLE PRECISION , - IDENTIFYING CHAR(1) NOT NULL , + JOB_EXECUTION_ID BIGINT NOT NULL, + TYPE_CD VARCHAR(6) NOT NULL, + KEY_NAME VARCHAR(100) NOT NULL, + STRING_VAL VARCHAR(250), + DATE_VAL TIMESTAMP DEFAULT NULL, + LONG_VAL BIGINT, + DOUBLE_VAL DOUBLE PRECISION, + IDENTIFYING CHAR(1) NOT NULL, constraint JOB_EXEC_PARAMS_FK foreign key (JOB_EXECUTION_ID) references PREFIX_JOB_EXECUTION(JOB_EXECUTION_ID) ) ; CREATE TABLE PREFIX_STEP_EXECUTION ( - STEP_EXECUTION_ID BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY , + STEP_EXECUTION_ID BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, VERSION BIGINT NOT NULL, STEP_NAME VARCHAR(100) NOT NULL, JOB_EXECUTION_ID BIGINT NOT NULL, - START_TIME TIMESTAMP NOT NULL , - END_TIME TIMESTAMP DEFAULT NULL , - STATUS VARCHAR(10) , - COMMIT_COUNT BIGINT , - READ_COUNT BIGINT , - FILTER_COUNT BIGINT , - WRITE_COUNT BIGINT , - READ_SKIP_COUNT BIGINT , - WRITE_SKIP_COUNT BIGINT , - PROCESS_SKIP_COUNT BIGINT , - ROLLBACK_COUNT BIGINT , - EXIT_CODE VARCHAR(2500) , - EXIT_MESSAGE VARCHAR(2500) , + START_TIME TIMESTAMP NOT NULL, + END_TIME TIMESTAMP DEFAULT NULL, + STATUS VARCHAR(10), + COMMIT_COUNT BIGINT, + READ_COUNT BIGINT, + FILTER_COUNT BIGINT, + WRITE_COUNT BIGINT, + READ_SKIP_COUNT BIGINT, + WRITE_SKIP_COUNT BIGINT, + PROCESS_SKIP_COUNT BIGINT, + ROLLBACK_COUNT BIGINT, + EXIT_CODE VARCHAR(2500), + EXIT_MESSAGE VARCHAR(2500), LAST_UPDATED TIMESTAMP, constraint JOB_EXEC_STEP_FK foreign key (JOB_EXECUTION_ID) references PREFIX_JOB_EXECUTION(JOB_EXECUTION_ID) @@ -61,7 +61,7 @@ CREATE TABLE PREFIX_STEP_EXECUTION ( CREATE TABLE PREFIX_STEP_EXECUTION_CONTEXT ( STEP_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY, SHORT_CONTEXT VARCHAR(2500) NOT NULL, - SERIALIZED_CONTEXT LONGVARCHAR , + SERIALIZED_CONTEXT LONGVARCHAR, constraint STEP_EXEC_CTX_FK foreign key (STEP_EXECUTION_ID) references PREFIX_STEP_EXECUTION(STEP_EXECUTION_ID) ) ; @@ -69,7 +69,7 @@ CREATE TABLE PREFIX_STEP_EXECUTION_CONTEXT ( CREATE TABLE PREFIX_JOB_EXECUTION_CONTEXT ( JOB_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY, SHORT_CONTEXT VARCHAR(2500) NOT NULL, - SERIALIZED_CONTEXT LONGVARCHAR , + SERIALIZED_CONTEXT LONGVARCHAR, constraint JOB_EXEC_CTX_FK foreign key (JOB_EXECUTION_ID) references PREFIX_JOB_EXECUTION(JOB_EXECUTION_ID) ) ; diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/io/rest-client.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/io/rest-client.adoc index 40fac8b9a484..6fbbf6dbaed8 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/io/rest-client.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/io/rest-client.adoc @@ -209,8 +209,8 @@ If multiple clients are available on the classpath, and not global configuration [[io.rest-client.clienthttprequestfactory.configuration]] === Global HTTP Client Configuration -If the the auto-detected HTTP client does not meet your needs, you can use the configprop:spring.http.client.factory[] property to pick a specific factory. -For example, if you have Apache HttpClient on your classpath, but you prefer Jetty's javadoc:org.eclipse.jetty.client.HttpClient[] you can add use the following: +If the auto-detected HTTP client does not meet your needs, you can use the configprop:spring.http.client.factory[] property to pick a specific factory. +For example, if you have Apache HttpClient on your classpath, but you prefer Jetty's javadoc:org.eclipse.jetty.client.HttpClient[] you can add the following: [configprops,yaml] ---- diff --git a/spring-boot-project/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/restclient/clienthttprequestfactory/configuration/MyClientHttpConfiguration.kt b/spring-boot-project/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/restclient/clienthttprequestfactory/configuration/MyClientHttpConfiguration.kt index d3a7827b109c..9ffd8489c677 100644 --- a/spring-boot-project/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/restclient/clienthttprequestfactory/configuration/MyClientHttpConfiguration.kt +++ b/spring-boot-project/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/restclient/clienthttprequestfactory/configuration/MyClientHttpConfiguration.kt @@ -10,7 +10,7 @@ import java.net.http.HttpClient class MyClientHttpConfiguration { @Bean - fun clientHttpRequestFactoryBuilder(proxySelector: ProxySelector): ClientHttpRequestFactoryBuilder<*>? { + fun clientHttpRequestFactoryBuilder(proxySelector: ProxySelector): ClientHttpRequestFactoryBuilder<*> { return ClientHttpRequestFactoryBuilder.jdk() .withHttpClientCustomizer { builder -> builder.proxy(proxySelector) } } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/json/app/ExampleJsonComponent.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/json/app/ExampleJsonComponent.java index 3cb4698f56a4..3817f7d98249 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/json/app/ExampleJsonComponent.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/json/app/ExampleJsonComponent.java @@ -59,7 +59,7 @@ static class Deserializer extends JsonObjectDeserializer { protected ExampleCustomObject deserializeObject(JsonParser jsonParser, DeserializationContext context, ObjectCodec codec, JsonNode tree) throws IOException { String value = nullSafeValue(tree.get("value"), String.class); - Date date = nullSafeValue(tree.get("date"), Integer.class, Date::new); + Date date = nullSafeValue(tree.get("date"), Long.class, Date::new); UUID uuid = nullSafeValue(tree.get("uuid"), String.class, UUID::fromString); return new ExampleCustomObject(value, date, uuid); } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/json-shade/java/org/springframework/boot/configurationprocessor/json/JSONObject.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/json-shade/java/org/springframework/boot/configurationprocessor/json/JSONObject.java index acf177a7508e..8bb808fff37c 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/json-shade/java/org/springframework/boot/configurationprocessor/json/JSONObject.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/json-shade/java/org/springframework/boot/configurationprocessor/json/JSONObject.java @@ -786,7 +786,7 @@ public static String quote(String data) { /** * Wraps the given object if necessary. *

    - * If the object is null or , returns {@link #NULL}. If the object is a + * If the object is null or, returns {@link #NULL}. If the object is a * {@code JSONArray} or {@code JSONObject}, no wrapping is necessary. If the object is * {@code NULL}, no wrapping is necessary. If the object is an array or * {@code Collection}, returns an equivalent {@code JSONArray}. If the object is a diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/util/Instantiator.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/util/Instantiator.java index b752e86a77a8..87d2d300d433 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/util/Instantiator.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/util/Instantiator.java @@ -149,9 +149,9 @@ public T instantiate(ClassLoader classLoader, String name) { } /** - * Instantiate the given set of classes, injecting constructor arguments as necessary. - * @param type the types to instantiate - * @return a list of instantiated instances + * Instantiate the given class, injecting constructor arguments as necessary. + * @param type the type to instantiate + * @return an instantiated instance * @since 3.4.0 */ public T instantiateType(Class type) { diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/RestTemplateBuilder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/RestTemplateBuilder.java index 5c9821e7dcf1..3862e9c0d04d 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/RestTemplateBuilder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/RestTemplateBuilder.java @@ -438,7 +438,7 @@ this.errorHandler, this.basicAuthentication, append(this.defaultHeaders, name, v /** * Sets the {@link ClientHttpRequestFactorySettings}. This will replace any previously - * set {@link #connectTimeout(Duration) connectTimeout} ,{@link #readTimeout(Duration) + * set {@link #connectTimeout(Duration) connectTimeout}, {@link #readTimeout(Duration) * readTimeout} and {@link #sslBundle(SslBundle) sslBundle} values. * @param requestFactorySettings the request factory settings * @return a new builder instance diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/context/ServerPortInfoApplicationContextInitializer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/context/ServerPortInfoApplicationContextInitializer.java index 2ec73ab57a12..80394628a08c 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/context/ServerPortInfoApplicationContextInitializer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/context/ServerPortInfoApplicationContextInitializer.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -39,7 +39,7 @@ * {@link Value @Value} or obtained through the {@link Environment}. *

    * If the {@link WebServerInitializedEvent} has a - * {@link WebServerApplicationContext#getServerNamespace() server namespace} , it will be + * {@link WebServerApplicationContext#getServerNamespace() server namespace}, it will be * used to construct the property name. For example, the "management" actuator context * will have the property name {@literal "local.management.port"}. *

    diff --git a/spring-boot-tests/spring-boot-integration-tests/spring-boot-server-tests/src/intTest/java/org/springframework/boot/context/embedded/EmbeddedServerContainerInvocationContextProvider.java b/spring-boot-tests/spring-boot-integration-tests/spring-boot-server-tests/src/intTest/java/org/springframework/boot/context/embedded/EmbeddedServerContainerInvocationContextProvider.java index 4ed867e3ee03..c7328fc8a203 100644 --- a/spring-boot-tests/spring-boot-integration-tests/spring-boot-server-tests/src/intTest/java/org/springframework/boot/context/embedded/EmbeddedServerContainerInvocationContextProvider.java +++ b/spring-boot-tests/spring-boot-integration-tests/spring-boot-server-tests/src/intTest/java/org/springframework/boot/context/embedded/EmbeddedServerContainerInvocationContextProvider.java @@ -116,8 +116,9 @@ private void cleanupCaches() { private AbstractApplicationLauncher getAbstractApplicationLauncher(Application application, Class launcherClass) { String cacheKey = application.getContainer() + ":" + application.getPackaging() + ":" + launcherClass.getName(); - if (this.launcherCache.containsKey(cacheKey)) { - return this.launcherCache.get(cacheKey); + AbstractApplicationLauncher cachedLauncher = this.launcherCache.get(cacheKey); + if (cachedLauncher != null) { + return cachedLauncher; } AbstractApplicationLauncher launcher = ReflectionUtils.newInstance(launcherClass, application, new File(buildOutput.getRootLocation(), "app-launcher-" + UUID.randomUUID())); From fbf981ca0a0c867d96ed616beb91f620bf634e6f Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Fri, 13 Dec 2024 13:56:12 -0800 Subject: [PATCH 154/203] Run PaketoBuilderTests on all JDK versions Closes gh-43505 --- .../springframework/boot/image/paketo/PaketoBuilderTests.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/spring-boot-system-tests/spring-boot-image-tests/src/systemTest/java/org/springframework/boot/image/paketo/PaketoBuilderTests.java b/spring-boot-system-tests/spring-boot-image-tests/src/systemTest/java/org/springframework/boot/image/paketo/PaketoBuilderTests.java index fc447cc0ad90..687b3916164e 100644 --- a/spring-boot-system-tests/spring-boot-image-tests/src/systemTest/java/org/springframework/boot/image/paketo/PaketoBuilderTests.java +++ b/spring-boot-system-tests/spring-boot-image-tests/src/systemTest/java/org/springframework/boot/image/paketo/PaketoBuilderTests.java @@ -35,8 +35,6 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.EnabledForJreRange; -import org.junit.jupiter.api.condition.JRE; import org.junit.jupiter.api.extension.ExtendWith; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.wait.strategy.Wait; @@ -63,7 +61,6 @@ * @author Scott Frederick */ @ExtendWith({ GradleBuildInjectionExtension.class, GradleBuildExtension.class }) -@EnabledForJreRange(max = JRE.JAVA_21) class PaketoBuilderTests { GradleBuild gradleBuild; From 6d09459cfce484cb9835489186a93ac6f4058b3f Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Fri, 13 Dec 2024 19:01:45 -0800 Subject: [PATCH 155/203] Improve error message when unable to find `@SpringBootConfiguration` Closes gh-43357 --- .../test/context/SpringBootTestContextBootstrapper.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootTestContextBootstrapper.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootTestContextBootstrapper.java index 40970888546f..27532bca5edc 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootTestContextBootstrapper.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootTestContextBootstrapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -243,8 +243,11 @@ private Class findConfigurationClass(Class testClass) { return ClassUtils.resolveClassName(foundClassName, testClass.getClassLoader()); } Class found = new AnnotatedClassFinder(SpringBootConfiguration.class).findFromClass(testClass); - Assert.state(found != null, "Unable to find a @SpringBootConfiguration, you need to use " - + "@ContextConfiguration or @SpringBootTest(classes=...) with your test"); + Assert.state(found != null, + "Unable to find a @SpringBootConfiguration by searching packages upwards from the test. " + + "You can use @ContextConfiguration, @SpringBootTest(classes=...) or other Spring Test " + + "supported mechanisms to explicitly declare the configuration classes to load. Classes " + + "annotated with @TestConfiguration are not considered."); this.aotTestAttributes.setAttribute(propertyName, found.getName()); return found; } From 45da43c6b475fb0cde6ceb3aa87e9b440266e63b Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Fri, 13 Dec 2024 19:03:43 -0800 Subject: [PATCH 156/203] Update copyright year of changed files --- .../springframework/boot/autoconfigure/AutoConfiguration.java | 2 +- .../boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.java | 2 +- .../groovy/template/GroovyTemplateAutoConfigurationTests.java | 2 +- .../boot/autoconfigure/kafka/KafkaPropertiesTests.java | 2 +- .../boot/autoconfigure/orm/jpa/HibernatePropertiesTests.java | 2 +- .../boot/autoconfigure/validation/ValidatorAdapterTests.java | 2 +- .../org/springframework/boot/loader/jar/StringSequence.java | 2 +- .../smoketest/actuator/ui/SampleActuatorUiApplicationTests.java | 2 +- .../java/smoketest/servlet/SampleServletApplicationTests.java | 2 +- .../security/method/SampleMethodSecurityApplicationTests.java | 2 +- .../secure/custom/SampleWebSecureCustomApplicationTests.java | 2 +- .../web/secure/jdbc/SampleWebSecureJdbcApplicationTests.java | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfiguration.java index 0bf59e966ab5..7e96cdc604d8 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.java index 913d32cfa890..fe8b19db079a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/groovy/template/GroovyTemplateAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/groovy/template/GroovyTemplateAutoConfigurationTests.java index 85d96c607917..03a0d821181e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/groovy/template/GroovyTemplateAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/groovy/template/GroovyTemplateAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaPropertiesTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaPropertiesTests.java index f00ddd930bef..f6d45dfd0a69 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaPropertiesTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaPropertiesTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernatePropertiesTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernatePropertiesTests.java index d095e367b1a2..686e7d1ec239 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernatePropertiesTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernatePropertiesTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/validation/ValidatorAdapterTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/validation/ValidatorAdapterTests.java index 8a3cb76bc80a..4123d8732174 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/validation/ValidatorAdapterTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/validation/ValidatorAdapterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader-classic/src/main/java/org/springframework/boot/loader/jar/StringSequence.java b/spring-boot-project/spring-boot-tools/spring-boot-loader-classic/src/main/java/org/springframework/boot/loader/jar/StringSequence.java index 69ae7d6cae7f..e63ac6970cfa 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-loader-classic/src/main/java/org/springframework/boot/loader/jar/StringSequence.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader-classic/src/main/java/org/springframework/boot/loader/jar/StringSequence.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-actuator-ui/src/test/java/smoketest/actuator/ui/SampleActuatorUiApplicationTests.java b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-actuator-ui/src/test/java/smoketest/actuator/ui/SampleActuatorUiApplicationTests.java index e098c5b3192b..40f08308d375 100644 --- a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-actuator-ui/src/test/java/smoketest/actuator/ui/SampleActuatorUiApplicationTests.java +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-actuator-ui/src/test/java/smoketest/actuator/ui/SampleActuatorUiApplicationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-servlet/src/test/java/smoketest/servlet/SampleServletApplicationTests.java b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-servlet/src/test/java/smoketest/servlet/SampleServletApplicationTests.java index f26adcd2d724..0f8762cdb735 100644 --- a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-servlet/src/test/java/smoketest/servlet/SampleServletApplicationTests.java +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-servlet/src/test/java/smoketest/servlet/SampleServletApplicationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-web-method-security/src/test/java/smoketest/security/method/SampleMethodSecurityApplicationTests.java b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-web-method-security/src/test/java/smoketest/security/method/SampleMethodSecurityApplicationTests.java index 6862a7303229..48309081eb55 100644 --- a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-web-method-security/src/test/java/smoketest/security/method/SampleMethodSecurityApplicationTests.java +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-web-method-security/src/test/java/smoketest/security/method/SampleMethodSecurityApplicationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2024 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. diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-web-secure-custom/src/test/java/smoketest/web/secure/custom/SampleWebSecureCustomApplicationTests.java b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-web-secure-custom/src/test/java/smoketest/web/secure/custom/SampleWebSecureCustomApplicationTests.java index d87f39e69c71..795c4b3ef7e8 100644 --- a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-web-secure-custom/src/test/java/smoketest/web/secure/custom/SampleWebSecureCustomApplicationTests.java +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-web-secure-custom/src/test/java/smoketest/web/secure/custom/SampleWebSecureCustomApplicationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2024 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. diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-web-secure-jdbc/src/test/java/smoketest/web/secure/jdbc/SampleWebSecureJdbcApplicationTests.java b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-web-secure-jdbc/src/test/java/smoketest/web/secure/jdbc/SampleWebSecureJdbcApplicationTests.java index 5f7871f25e37..5494fa7196b3 100644 --- a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-web-secure-jdbc/src/test/java/smoketest/web/secure/jdbc/SampleWebSecureJdbcApplicationTests.java +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-web-secure-jdbc/src/test/java/smoketest/web/secure/jdbc/SampleWebSecureJdbcApplicationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2024 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. From 0c090b728a8a84a78d9a525a46fd988c1fd4b2bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Sat, 14 Dec 2024 11:17:37 +0100 Subject: [PATCH 157/203] Upgrade to Hibernate Validator 8.0.2.Final Closes gh-43509 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 95f6c60d25d9..6a7b57d4a753 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -545,7 +545,7 @@ bom { .formatted(version.major(), version.minor())) } } - library("Hibernate Validator", "8.0.1.Final") { + library("Hibernate Validator", "8.0.2.Final") { group("org.hibernate.validator") { modules = [ "hibernate-validator", From 11cb3290705b79ddbf567b83c3c3fdd6f6d77265 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Sat, 14 Dec 2024 11:17:37 +0100 Subject: [PATCH 158/203] Upgrade to Spring Retry 2.0.11 Closes gh-43485 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 6a7b57d4a753..05d8c267fc9a 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2307,7 +2307,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-restdocs/releases/tag/v{version}") } } - library("Spring Retry", "2.0.11-SNAPSHOT") { + library("Spring Retry", "2.0.11") { considerSnapshots() group("org.springframework.retry") { modules = [ From 6cec79df6351a7f4f9c9e3594716c4adadf7c19d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Sat, 14 Dec 2024 11:17:53 +0100 Subject: [PATCH 159/203] Upgrade to Hibernate Validator 8.0.2.Final Closes gh-43510 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index fec1086c7c95..954c5c84b44c 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -546,7 +546,7 @@ bom { .formatted(version.major(), version.minor())) } } - library("Hibernate Validator", "8.0.1.Final") { + library("Hibernate Validator", "8.0.2.Final") { group("org.hibernate.validator") { modules = [ "hibernate-validator", From 312c2d3e3c17f7ecd4ae64f4d123c7a9976b3254 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Sat, 14 Dec 2024 11:17:54 +0100 Subject: [PATCH 160/203] Upgrade to Spring Retry 2.0.11 Closes gh-43486 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 954c5c84b44c..f3ec8d858fcc 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2290,7 +2290,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-restdocs/releases/tag/v{version}") } } - library("Spring Retry", "2.0.11-SNAPSHOT") { + library("Spring Retry", "2.0.11") { considerSnapshots() group("org.springframework.retry") { modules = [ From 0ac3f8dd1f414c1c066d5ff9dce10a9d53cd07a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Sat, 14 Dec 2024 17:20:13 +0100 Subject: [PATCH 161/203] Switch spring-retry javadoc links back to docs.spring.io Closes gh-43231 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 05d8c267fc9a..49fa03363728 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2316,7 +2316,7 @@ bom { } links { site("https://github.com/spring-projects/spring-retry") - javadoc("https://javadoc.io/doc/org.springframework.retry/spring-retry/{version}", "org.springframework.retry") + javadoc("https://docs.spring.io/spring-retry/docs/{version}/apidocs", "org.springframework.retry") releaseNotes("https://github.com/spring-projects/spring-retry/releases/tag/v{version}") } } From 7832d3be73c147bcde786b31d2242353de045c8e Mon Sep 17 00:00:00 2001 From: Tran Ngoc Nhan Date: Sat, 14 Dec 2024 21:27:29 +0700 Subject: [PATCH 162/203] Fix typo See gh-43512 --- .../src/docs/antora/modules/gradle-plugin/pages/reacting.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/pages/reacting.adoc b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/pages/reacting.adoc index ddf0b0ed51a4..40ab1ab2e557 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/pages/reacting.adoc +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/pages/reacting.adoc @@ -17,7 +17,7 @@ When Gradle's {url-gradle-docs-java-plugin}[`java` plugin] is applied to a proje 3. Configures the `jar` task to use `plain` as the convention for its archive classifier. 4. Creates a {apiref-gradle-plugin-boot-build-image}[`BootBuildImage`] task named `bootBuildImage` that will create a OCI image using a https://buildpacks.io[buildpack]. 5. Creates a {apiref-gradle-plugin-boot-run}[`BootRun`] task named `bootRun` that can be used to run your application using the `main` source set to find its main method and provide its runtime classpath. -6. Creates a {apiref-gradle-plugin-boot-run}['BootRun`] task named `bootTestRun` that can be used to run your application using the `test` source set to find its main method and provide its runtime classpath. +6. Creates a {apiref-gradle-plugin-boot-run}[`BootRun`] task named `bootTestRun` that can be used to run your application using the `test` source set to find its main method and provide its runtime classpath. 7. Creates a configuration named `bootArchives` that contains the artifact produced by the `bootJar` task. 8. Creates a configuration named `developmentOnly` for dependencies that are only required at development time, such as Spring Boot's Devtools, and should not be packaged in executable jars and wars. 9. Creates a configuration named `testAndDevelopmentOnly` for dependencies that are only required at development time and when writing and running tests and that should not be packaged in executable jars and wars. From 239fa0356f931c70731a78b72ff3afbbd01ee7f3 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Mon, 16 Dec 2024 10:43:35 -0800 Subject: [PATCH 163/203] Remove trailing slashes from all link URLs Closes gh-43518 --- .../antora/AntoraAsciidocAttributes.java | 2 +- .../spring-boot-dependencies/build.gradle | 36 +++++++++---------- .../spring-boot-gradle-plugin/build.gradle | 4 +-- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/buildSrc/src/main/java/org/springframework/boot/build/antora/AntoraAsciidocAttributes.java b/buildSrc/src/main/java/org/springframework/boot/build/antora/AntoraAsciidocAttributes.java index f82a828a9945..bd03c76612ad 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/antora/AntoraAsciidocAttributes.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/antora/AntoraAsciidocAttributes.java @@ -202,7 +202,7 @@ private void addArtifactAttributes(Map attributes) { } private void addUrlJava(Map attributes) { - attributes.put("url-javase-javadoc", "https://docs.oracle.com/en/java/javase/17/docs/api/"); + attributes.put("url-javase-javadoc", "https://docs.oracle.com/en/java/javase/17/docs/api"); attributes.put("javadoc-location-java-beans", "{url-javase-javadoc}/java.desktop"); attributes.put("javadoc-location-java-lang", "{url-javase-javadoc}/java.base"); attributes.put("javadoc-location-java-net", "{url-javase-javadoc}/java.base"); diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 49fa03363728..a1db326b2fc1 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -86,7 +86,7 @@ bom { ] } links { - site("https://assertj.github.io/doc/") + site("https://assertj.github.io/doc") releaseNotes("https://github.com/assertj/assertj/releases/tag/assertj-build-{version}") } } @@ -145,7 +145,7 @@ bom { ] } links { - site("https://bytebuddy.net/") + site("https://bytebuddy.net") docs("https://bytebuddy.net/#/tutorial") releaseNotes("https://github.com/raphw/byte-buddy/releases/tag/byte-buddy-{version}") } @@ -298,7 +298,7 @@ bom { } links { site("https://github.com/spring-gradle-plugins/dependency-management-plugin") - docs("https://docs.spring.io/dependency-management-plugin/docs/{version}/reference/html/") + docs("https://docs.spring.io/dependency-management-plugin/docs/{version}/reference/html") releaseNotes("https://github.com/spring-gradle-plugins/dependency-management-plugin/releases/tag/v{version}") } } @@ -333,7 +333,7 @@ bom { ] } links { - site("https://www.ehcache.org/") + site("https://www.ehcache.org") releaseNotes("https://github.com/ehcache/ehcache3/releases/tag/v{version}") } } @@ -449,7 +449,7 @@ bom { ] } links { - site("https://www.graphql-java.com/") + site("https://www.graphql-java.com") javadoc("https://javadoc.io/doc/com.graphql-java/graphql-java/{version}", "graphql.schema", "graphql.execution") releaseNotes("https://github.com/graphql-java/graphql-java/releases/tag/v{version}") } @@ -509,7 +509,7 @@ bom { } links { site("https://hazelcast.com") - javadoc("https://docs.hazelcast.org/docs/{version}/javadoc/", "com.hazelcast") + javadoc("https://docs.hazelcast.org/docs/{version}/javadoc", "com.hazelcast") releaseNotes("https://github.com/hazelcast/hazelcast/releases/tag/v{version}") } } @@ -630,7 +630,7 @@ bom { ] } links { - site("https://infinispan.org/") + site("https://infinispan.org") javadoc(version -> "https://docs.jboss.org/infinispan/%s.%s/apidocs".formatted(version.major(), version.minor()), "org.infinispan") releaseNotes("https://github.com/infinispan/infinispan/releases/tag/{version}") } @@ -1138,7 +1138,7 @@ bom { ] } links { - site("https://kotlinlang.org/") + site("https://kotlinlang.org") docs("https://kotlinlang.org/docs/reference") releaseNotes("https://github.com/JetBrains/kotlin/releases/tag/v{version}") } @@ -1228,7 +1228,7 @@ bom { } links { site("https://projectlombok.org") - javadoc("https://projectlombok.org/api/") + javadoc("https://projectlombok.org/api") } } library("MariaDB", "3.3.3") { @@ -1238,8 +1238,8 @@ bom { ] } links { - site("https://mariadb.com/kb/en/mariadb-connector-j/") - releaseNotes(version -> "https://mariadb.com/kb/en/mariadb-connector-j-%s-release-notes/" + site("https://mariadb.com/kb/en/mariadb-connector-j") + releaseNotes(version -> "https://mariadb.com/kb/en/mariadb-connector-j-%s-release-notes" .formatted(version.toString("-"))) } } @@ -1463,7 +1463,7 @@ bom { ] } links { - site("https://site.mockito.org/") + site("https://site.mockito.org") releaseNotes("https://github.com/mockito/mockito/releases/tag/v{version}") } } @@ -1871,7 +1871,7 @@ bom { } links { site("https://github.com/rabbitmq/rabbitmq-java-client") - javadoc("https://rabbitmq.github.io/rabbitmq-java-client/api/current/", "com.rabbitmq") + javadoc("https://rabbitmq.github.io/rabbitmq-java-client/api/current", "com.rabbitmq") releaseNotes("https://github.com/rabbitmq/rabbitmq-java-client/releases/tag/v{version}") } } @@ -1902,7 +1902,7 @@ bom { ] } links { - site("https://projectreactor.io/") + site("https://projectreactor.io") releaseNotes("https://github.com/reactor/reactor/releases/tag/{version}") } } @@ -2283,7 +2283,7 @@ bom { links { site("https://spring.io/projects/spring-pulsar") github("https://github.com/spring-projects/spring-pulsar") - javadoc(version -> "https://docs.spring.io/spring-pulsar/docs/%s/api/" + javadoc(version -> "https://docs.spring.io/spring-pulsar/docs/%s/api" .formatted(version.forMajorMinorGeneration()), "org.springframework.pulsar") docs(version -> "https://docs.spring.io/spring-pulsar/docs/%s/reference" .formatted(version.forMajorMinorGeneration())) @@ -2300,9 +2300,9 @@ bom { links { site("https://spring.io/projects/spring-restdocs") github("https://github.com/spring-projects/spring-restdocs") - javadoc(version -> "https://docs.spring.io/spring-restdocs/docs/%s/api/" + javadoc(version -> "https://docs.spring.io/spring-restdocs/docs/%s/api" .formatted(version.forMajorMinorGeneration()), "org.springframework.restdocs") - docs(version -> "https://docs.spring.io/spring-restdocs/docs/%s/reference/htmlsingle/" + docs(version -> "https://docs.spring.io/spring-restdocs/docs/%s/reference/htmlsingle" .formatted(version.forMajorMinorGeneration())) releaseNotes("https://github.com/spring-projects/spring-restdocs/releases/tag/v{version}") } @@ -2406,7 +2406,7 @@ bom { ] } links { - site("https://www.thymeleaf.org/") + site("https://www.thymeleaf.org") javadoc("thymeleaf", version -> "https://www.thymeleaf.org/apidocs/thymeleaf/%s".formatted(version), "org.thymeleaf") javadoc("thymeleaf-spring6", version -> "https://www.thymeleaf.org/apidocs/thymeleaf-spring6/%s".formatted(version), "org.thymeleaf.spring6") releaseNotes("https://github.com/thymeleaf/thymeleaf/releases/tag/thymeleaf-{version}") diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/build.gradle b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/build.gradle index 338335ea49c6..82bd14d33548 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/build.gradle +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/build.gradle @@ -160,8 +160,8 @@ javadoc { splitIndex = true use = true windowTitle = "Spring Boot Gradle Plugin ${project.version} API" - links "https://docs.gradle.org/$gradle.gradleVersion/javadoc/" - links "https://docs.oracle.com/en/java/javase/17/docs/api/" + links "https://docs.gradle.org/$gradle.gradleVersion/javadoc" + links "https://docs.oracle.com/en/java/javase/17/docs/api" } } From 843a4d5658461407663f22bb0a58431a370bc76f Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 16 Dec 2024 19:15:41 +0000 Subject: [PATCH 164/203] Upgrade to Spring Kafka 3.2.6 Closes gh-43394 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index a1db326b2fc1..0f8198367c2c 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2235,7 +2235,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-integration/releases/tag/v{version}") } } - library("Spring Kafka", "3.2.6-SNAPSHOT") { + library("Spring Kafka", "3.2.6") { considerSnapshots() group("org.springframework.kafka") { modules = [ From e6e1274bf706f2fe5249c1081c2d4d459f8aa9d6 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 16 Dec 2024 19:15:46 +0000 Subject: [PATCH 165/203] Upgrade to Spring Security 6.3.6 Closes gh-43527 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 0f8198367c2c..7dc9ec881f13 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2320,7 +2320,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-retry/releases/tag/v{version}") } } - library("Spring Security", "6.3.5") { + library("Spring Security", "6.3.6") { considerSnapshots() group("org.springframework.security") { imports = [ From 65deba8dbbd02a07eea0a0f3e4d2816a2b96f96f Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 16 Dec 2024 19:18:01 +0000 Subject: [PATCH 166/203] Upgrade to Byte Buddy 1.15.11 Closes gh-43529 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index b328731759f5..3b2074aa65ef 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -137,7 +137,7 @@ bom { releaseNotes("https://github.com/mojohaus/build-helper-maven-plugin/releases/tag/{version}") } } - library("Byte Buddy", "1.15.10") { + library("Byte Buddy", "1.15.11") { group("net.bytebuddy") { modules = [ "byte-buddy", From c58c2bb2abc3cd8e9ad23f274acb0a0074a5908a Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 16 Dec 2024 19:18:06 +0000 Subject: [PATCH 167/203] Upgrade to JUnit Jupiter 5.11.4 Closes gh-43530 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 2ab7e8948c3d..0beda7f9910c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,7 +13,7 @@ graalVersion=22.3 hamcrestVersion=2.2 jacksonVersion=2.18.2 javaFormatVersion=0.0.43 -junitJupiterVersion=5.11.3 +junitJupiterVersion=5.11.4 kotlinVersion=1.9.25 mavenVersion=3.9.4 mockitoVersion=5.14.2 From cadeb6d88fdf1a1fe8e521cbab33c56ab19c3c90 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 16 Dec 2024 19:18:06 +0000 Subject: [PATCH 168/203] Upgrade to Spring AMQP 3.2.1 Closes gh-43411 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 3b2074aa65ef..8741f356844f 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2081,7 +2081,7 @@ bom { ] } } - library("Spring AMQP", "3.2.1-SNAPSHOT") { + library("Spring AMQP", "3.2.1") { considerSnapshots() group("org.springframework.amqp") { imports = [ From a25065e3832f16e623a3e0197cda15ebaf3b09ad Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 16 Dec 2024 19:18:07 +0000 Subject: [PATCH 169/203] Upgrade to Spring Security 6.4.2 Closes gh-43419 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 8741f356844f..eda212930ec5 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2303,7 +2303,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-retry/releases/tag/v{version}") } } - library("Spring Security", "6.4.2-SNAPSHOT") { + library("Spring Security", "6.4.2") { considerSnapshots() group("org.springframework.security") { imports = [ From f1c129130169191804e62c31b061463ae5779eca Mon Sep 17 00:00:00 2001 From: Chris Bono Date: Mon, 16 Dec 2024 14:45:13 -0600 Subject: [PATCH 170/203] Add Pulsar 4.0.x smoke test This commit adds a smoke test to verify basic functionality with the Pulsar 4.0.x client. See gh-43532 --- .../build.gradle | 27 ++++++ .../pulsar/SamplePulsarApplicationTests.java | 92 +++++++++++++++++++ .../smoketest/pulsar/ImperativeAppConfig.java | 59 ++++++++++++ .../smoketest/pulsar/ReactiveAppConfig.java | 64 +++++++++++++ .../java/smoketest/pulsar/SampleMessage.java | 20 ++++ .../pulsar/SamplePulsarApplication.java | 29 ++++++ .../src/main/resources/application.properties | 1 + 7 files changed, 292 insertions(+) create mode 100644 spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-pulsar4/build.gradle create mode 100644 spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-pulsar4/src/dockerTest/java/smoketest/pulsar/SamplePulsarApplicationTests.java create mode 100644 spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-pulsar4/src/main/java/smoketest/pulsar/ImperativeAppConfig.java create mode 100644 spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-pulsar4/src/main/java/smoketest/pulsar/ReactiveAppConfig.java create mode 100644 spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-pulsar4/src/main/java/smoketest/pulsar/SampleMessage.java create mode 100644 spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-pulsar4/src/main/java/smoketest/pulsar/SamplePulsarApplication.java create mode 100644 spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-pulsar4/src/main/resources/application.properties diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-pulsar4/build.gradle b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-pulsar4/build.gradle new file mode 100644 index 000000000000..83a22c02c3bb --- /dev/null +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-pulsar4/build.gradle @@ -0,0 +1,27 @@ +plugins { + id "java" + id "org.springframework.boot.docker-test" +} + +description = "Spring Boot Pulsar 4 smoke test" + +configurations.all { + resolutionStrategy.eachDependency { + if (it.requested.group == 'org.apache.pulsar' && + !(it.requested.name.startsWith('pulsar-client-reactive'))) { + it.useVersion '4.0.1' + } + } +} + +dependencies { + dockerTestImplementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-test")) + dockerTestImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support-docker")) + dockerTestImplementation(project(":spring-boot-project:spring-boot-testcontainers")) + dockerTestImplementation("org.awaitility:awaitility") + dockerTestImplementation("org.testcontainers:junit-jupiter") + dockerTestImplementation("org.testcontainers:pulsar") + + implementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-pulsar")) + implementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-pulsar-reactive")) +} diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-pulsar4/src/dockerTest/java/smoketest/pulsar/SamplePulsarApplicationTests.java b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-pulsar4/src/dockerTest/java/smoketest/pulsar/SamplePulsarApplicationTests.java new file mode 100644 index 000000000000..5de0fad211c2 --- /dev/null +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-pulsar4/src/dockerTest/java/smoketest/pulsar/SamplePulsarApplicationTests.java @@ -0,0 +1,92 @@ +/* + * Copyright 2012-2024 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package smoketest.pulsar; + +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.IntStream; + +import org.awaitility.Awaitility; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.testcontainers.containers.PulsarContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.system.CapturedOutput; +import org.springframework.boot.test.system.OutputCaptureExtension; +import org.springframework.boot.testcontainers.service.connection.ServiceConnection; +import org.springframework.boot.testsupport.container.TestImage; +import org.springframework.test.context.ActiveProfiles; + +import static org.assertj.core.api.Assertions.assertThat; + +@Testcontainers(disabledWithoutDocker = true) +@ExtendWith(OutputCaptureExtension.class) +class SamplePulsarApplicationTests { + + @Container + @ServiceConnection + static final PulsarContainer pulsar = TestImage.container(PulsarContainer.class); + + abstract class PulsarApplication { + + private final String type; + + PulsarApplication(String type) { + this.type = type; + } + + @Test + void appProducesAndConsumesMessages(CapturedOutput output) { + List expectedOutput = new ArrayList<>(); + IntStream.range(0, 10).forEachOrdered((i) -> { + expectedOutput.add("++++++PRODUCE %s:(%s)------".formatted(this.type, i)); + expectedOutput.add("++++++CONSUME %s:(%s)------".formatted(this.type, i)); + }); + Awaitility.waitAtMost(Duration.ofSeconds(30)) + .untilAsserted(() -> assertThat(output).contains(expectedOutput)); + } + + } + + @Nested + @SpringBootTest + @ActiveProfiles("smoketest.pulsar.imperative") + class ImperativePulsarApplication extends PulsarApplication { + + ImperativePulsarApplication() { + super("IMPERATIVE"); + } + + } + + @Nested + @SpringBootTest + @ActiveProfiles("smoketest.pulsar.reactive") + class ReactivePulsarApplication extends PulsarApplication { + + ReactivePulsarApplication() { + super("REACTIVE"); + } + + } + +} diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-pulsar4/src/main/java/smoketest/pulsar/ImperativeAppConfig.java b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-pulsar4/src/main/java/smoketest/pulsar/ImperativeAppConfig.java new file mode 100644 index 000000000000..7964a3ad44ce --- /dev/null +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-pulsar4/src/main/java/smoketest/pulsar/ImperativeAppConfig.java @@ -0,0 +1,59 @@ +/* + * Copyright 2012-2024 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package smoketest.pulsar; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.boot.ApplicationRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.pulsar.annotation.PulsarListener; +import org.springframework.pulsar.core.PulsarTemplate; +import org.springframework.pulsar.core.PulsarTopic; +import org.springframework.pulsar.core.PulsarTopicBuilder; + +@Configuration(proxyBeanMethods = false) +@Profile("smoketest.pulsar.imperative") +class ImperativeAppConfig { + + private static final Log logger = LogFactory.getLog(ImperativeAppConfig.class); + + private static final String TOPIC = "pulsar-smoke-test-topic"; + + @Bean + PulsarTopic pulsarTestTopic() { + return new PulsarTopicBuilder().name(TOPIC).numberOfPartitions(1).build(); + } + + @Bean + ApplicationRunner sendMessagesToPulsarTopic(PulsarTemplate template) { + return (args) -> { + for (int i = 0; i < 10; i++) { + template.send(TOPIC, new SampleMessage(i, "message:" + i)); + logger.info("++++++PRODUCE IMPERATIVE:(" + i + ")------"); + } + }; + } + + @PulsarListener(topics = TOPIC) + void consumeMessagesFromPulsarTopic(SampleMessage msg) { + logger.info("++++++CONSUME IMPERATIVE:(" + msg.id() + ")------"); + } + +} diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-pulsar4/src/main/java/smoketest/pulsar/ReactiveAppConfig.java b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-pulsar4/src/main/java/smoketest/pulsar/ReactiveAppConfig.java new file mode 100644 index 000000000000..506aa97bec5e --- /dev/null +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-pulsar4/src/main/java/smoketest/pulsar/ReactiveAppConfig.java @@ -0,0 +1,64 @@ +/* + * Copyright 2012-2024 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package smoketest.pulsar; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.pulsar.reactive.client.api.MessageSpec; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import org.springframework.boot.ApplicationRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.pulsar.core.PulsarTopic; +import org.springframework.pulsar.core.PulsarTopicBuilder; +import org.springframework.pulsar.reactive.config.annotation.ReactivePulsarListener; +import org.springframework.pulsar.reactive.core.ReactivePulsarTemplate; + +@Configuration(proxyBeanMethods = false) +@Profile("smoketest.pulsar.reactive") +class ReactiveAppConfig { + + private static final Log logger = LogFactory.getLog(ReactiveAppConfig.class); + + private static final String TOPIC = "pulsar-reactive-smoke-test-topic"; + + @Bean + PulsarTopic pulsarTestTopic() { + return new PulsarTopicBuilder().name(TOPIC).numberOfPartitions(1).build(); + } + + @Bean + ApplicationRunner sendMessagesToPulsarTopic(ReactivePulsarTemplate template) { + return (args) -> Flux.range(0, 10) + .map((i) -> new SampleMessage(i, "message:" + i)) + .map(MessageSpec::of) + .as((msgs) -> template.send(TOPIC, msgs)) + .doOnNext((sendResult) -> logger + .info("++++++PRODUCE REACTIVE:(" + sendResult.getMessageSpec().getValue().id() + ")------")) + .subscribe(); + } + + @ReactivePulsarListener(topics = TOPIC) + Mono consumeMessagesFromPulsarTopic(SampleMessage msg) { + logger.info("++++++CONSUME REACTIVE:(" + msg.id() + ")------"); + return Mono.empty(); + } + +} diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-pulsar4/src/main/java/smoketest/pulsar/SampleMessage.java b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-pulsar4/src/main/java/smoketest/pulsar/SampleMessage.java new file mode 100644 index 000000000000..3887ce61f13a --- /dev/null +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-pulsar4/src/main/java/smoketest/pulsar/SampleMessage.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2023 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package smoketest.pulsar; + +record SampleMessage(Integer id, String content) { +} diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-pulsar4/src/main/java/smoketest/pulsar/SamplePulsarApplication.java b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-pulsar4/src/main/java/smoketest/pulsar/SamplePulsarApplication.java new file mode 100644 index 000000000000..560967bb2d0d --- /dev/null +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-pulsar4/src/main/java/smoketest/pulsar/SamplePulsarApplication.java @@ -0,0 +1,29 @@ +/* + * Copyright 2012-2023 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package smoketest.pulsar; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SamplePulsarApplication { + + public static void main(String[] args) { + SpringApplication.run(SamplePulsarApplication.class, args); + } + +} diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-pulsar4/src/main/resources/application.properties b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-pulsar4/src/main/resources/application.properties new file mode 100644 index 000000000000..b1ae3ec6f4ee --- /dev/null +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-pulsar4/src/main/resources/application.properties @@ -0,0 +1 @@ +spring.pulsar.consumer.subscription.initial-position=earliest From 02f748bd2d1173e9ca66c193afff0c845cf87463 Mon Sep 17 00:00:00 2001 From: Chris Bono Date: Mon, 16 Dec 2024 16:41:12 -0600 Subject: [PATCH 171/203] Update version of Pulsar test container image This commit updates the version of the Pulsar container from 3.2.4 to 3.3.3 (the recommended version in the Spring Boot 3.4.x line). See gh-43534 --- .../springframework/boot/testsupport/container/TestImage.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-tools/spring-boot-test-support-docker/src/main/java/org/springframework/boot/testsupport/container/TestImage.java b/spring-boot-project/spring-boot-tools/spring-boot-test-support-docker/src/main/java/org/springframework/boot/testsupport/container/TestImage.java index a81a793bdda1..1f2ae35e032d 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-test-support-docker/src/main/java/org/springframework/boot/testsupport/container/TestImage.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-test-support-docker/src/main/java/org/springframework/boot/testsupport/container/TestImage.java @@ -206,7 +206,7 @@ public enum TestImage { /** * A container image suitable for testing Pulsar. */ - PULSAR("apachepulsar/pulsar", "3.2.4", () -> PulsarContainer.class, + PULSAR("apachepulsar/pulsar", "3.3.3", () -> PulsarContainer.class, (container) -> ((PulsarContainer) container).withStartupAttempts(2) .withStartupTimeout(Duration.ofMinutes(3))), From 21203f06ecb863bc174a4da2c7a86a5326c3e500 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Mon, 16 Dec 2024 17:14:16 -0800 Subject: [PATCH 172/203] Use deterministic ordering for inserted shutdown hooks Update `SpringApplicationShutdownHook` so the underlying set of `Runnable` instances are stored in a `LinkedHashSet` rather than a `Collections.newSetFromMap(new IdentityHashMap<>())`. This insures that shutdown hooks are run in the order that they are added. Fixes gh-43430 --- .../boot/SpringApplicationShutdownHook.java | 45 +++++++++++++++---- .../SpringApplicationShutdownHookTests.java | 22 ++++++++- 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplicationShutdownHook.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplicationShutdownHook.java index b609a9315747..8e5e4ad3a349 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplicationShutdownHook.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplicationShutdownHook.java @@ -17,7 +17,6 @@ package org.springframework.boot; import java.util.Collections; -import java.util.IdentityHashMap; import java.util.LinkedHashSet; import java.util.Set; import java.util.WeakHashMap; @@ -104,16 +103,16 @@ void deregisterFailedApplicationContext(ConfigurableApplicationContext applicati public void run() { Set contexts; Set closedContexts; - Set actions; + Set handlers; synchronized (SpringApplicationShutdownHook.class) { this.inProgress = true; contexts = new LinkedHashSet<>(this.contexts); closedContexts = new LinkedHashSet<>(this.closedContexts); - actions = new LinkedHashSet<>(this.handlers.getActions()); + handlers = new LinkedHashSet<>(this.handlers.getActions()); } contexts.forEach(this::closeAndWait); closedContexts.forEach(this::closeAndWait); - actions.forEach(Runnable::run); + handlers.forEach(Handler::run); } boolean isApplicationContextRegistered(ConfigurableApplicationContext context) { @@ -171,7 +170,7 @@ private void assertNotInProgress() { */ private final class Handlers implements SpringApplicationShutdownHandlers, Runnable { - private final Set actions = Collections.newSetFromMap(new IdentityHashMap<>()); + private final Set actions = new LinkedHashSet<>(); @Override public void add(Runnable action) { @@ -179,7 +178,7 @@ public void add(Runnable action) { addRuntimeShutdownHookIfNecessary(); synchronized (SpringApplicationShutdownHook.class) { assertNotInProgress(); - this.actions.add(action); + this.actions.add(new Handler(action)); } } @@ -188,11 +187,11 @@ public void remove(Runnable action) { Assert.notNull(action, "Action must not be null"); synchronized (SpringApplicationShutdownHook.class) { assertNotInProgress(); - this.actions.remove(action); + this.actions.remove(new Handler(action)); } } - Set getActions() { + Set getActions() { return this.actions; } @@ -204,6 +203,36 @@ public void run() { } + /** + * A single handler that uses object identity for {@link #equals(Object)} and + * {@link #hashCode()}. + * + * @param runnable the handler runner + */ + record Handler(Runnable runnable) { + + @Override + public int hashCode() { + return System.identityHashCode(this.runnable); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + return this.runnable == ((Handler) obj).runnable; + } + + void run() { + this.runnable.run(); + } + + } + /** * {@link ApplicationListener} to track closed contexts. */ diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationShutdownHookTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationShutdownHookTests.java index 0d821496e30d..4d4d56947d7b 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationShutdownHookTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationShutdownHookTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -26,6 +26,7 @@ import org.awaitility.Awaitility; import org.junit.jupiter.api.Test; +import org.mockito.InOrder; import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.InitializingBean; @@ -39,6 +40,8 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.assertThatIllegalStateException; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.mock; /** * Tests for {@link SpringApplicationShutdownHook}. @@ -203,6 +206,23 @@ void deregistersFailedContext() { assertThat(shutdownHook.isApplicationContextRegistered(context)).isFalse(); } + @Test + void handlersRunInDeterministicOrder() { + TestSpringApplicationShutdownHook shutdownHook = new TestSpringApplicationShutdownHook(); + Runnable r1 = mock(Runnable.class); + Runnable r2 = mock(Runnable.class); + Runnable r3 = mock(Runnable.class); + shutdownHook.getHandlers().add(r2); + shutdownHook.getHandlers().add(r1); + shutdownHook.getHandlers().add(r3); + shutdownHook.run(); + InOrder ordered = inOrder(r1, r2, r3); + ordered.verify(r2).run(); + ordered.verify(r1).run(); + ordered.verify(r3).run(); + ordered.verifyNoMoreInteractions(); + } + static class TestSpringApplicationShutdownHook extends SpringApplicationShutdownHook { private boolean runtimeShutdownHookAdded; From 17901065cab3b9a366687fb5f8cf7833e2d39303 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Tue, 17 Dec 2024 08:33:36 +0100 Subject: [PATCH 173/203] Upgrade to Pulsar Reactive 0.5.10 Closes gh-43539 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 7dc9ec881f13..c507710415b3 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -1732,7 +1732,7 @@ bom { releaseNotes("https://pulsar.apache.org/release-notes/versioned/pulsar-{version}") } } - library("Pulsar Reactive", "0.5.9") { + library("Pulsar Reactive", "0.5.10") { group("org.apache.pulsar") { modules = [ "pulsar-client-reactive-adapter", From 1ba5c5c85d30cb4bafed4edb9de098dd68e5b5d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Tue, 17 Dec 2024 08:33:42 +0100 Subject: [PATCH 174/203] Upgrade to Pulsar Reactive 0.5.10 Closes gh-43539 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index eda212930ec5..7249c444c452 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -1715,7 +1715,7 @@ bom { releaseNotes("https://pulsar.apache.org/release-notes/versioned/pulsar-{version}") } } - library("Pulsar Reactive", "0.5.9") { + library("Pulsar Reactive", "0.5.10") { group("org.apache.pulsar") { modules = [ "pulsar-client-reactive-adapter", From f7f9d6389c23cb1e5bf6b34740f8a4fda3f63560 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Tue, 17 Dec 2024 08:33:42 +0100 Subject: [PATCH 175/203] Upgrade to Spring Kafka 3.3.1 Closes gh-43416 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 7249c444c452..ab211fa253d5 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2218,7 +2218,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-integration/releases/tag/v{version}") } } - library("Spring Kafka", "3.3.1-SNAPSHOT") { + library("Spring Kafka", "3.3.1") { considerSnapshots() group("org.springframework.kafka") { modules = [ From b7214812524a912dceba14fc2965ec70505708a2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Dec 2024 19:33:32 +0000 Subject: [PATCH 176/203] Bump jfrog/setup-jfrog-cli from 4.5.0 to 4.5.2 Bumps [jfrog/setup-jfrog-cli](https://github.com/jfrog/setup-jfrog-cli) from 4.5.0 to 4.5.2. - [Release notes](https://github.com/jfrog/setup-jfrog-cli/releases) - [Commits](https://github.com/jfrog/setup-jfrog-cli/compare/040913fd7ac2a2bcb29a7e963ea99e7c309d63e5...dff217c085c17666e8849ebdbf29c8fe5e3995e6) --- updated-dependencies: - dependency-name: jfrog/setup-jfrog-cli dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] See gh-43531 --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ab701e252a85..51dccea7af90 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -78,7 +78,7 @@ jobs: runs-on: ${{ vars.UBUNTU_SMALL || 'ubuntu-latest' }} steps: - name: Set up JFrog CLI - uses: jfrog/setup-jfrog-cli@040913fd7ac2a2bcb29a7e963ea99e7c309d63e5 # v4.5.0 + uses: jfrog/setup-jfrog-cli@dff217c085c17666e8849ebdbf29c8fe5e3995e6 # v4.5.2 env: JF_ENV_SPRING: ${{ vars.COMMERCIAL && secrets.COMMERCIAL_JF_ARTIFACTORY_SPRING || secrets.JF_ARTIFACTORY_SPRING }} - name: Promote open source build From b27f90880958b0073a0935bdb3cd111bded864e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Tue, 17 Dec 2024 09:05:54 +0100 Subject: [PATCH 177/203] Polish "Bump jfrog/setup-jfrog-cli from 4.5.0 to 4.5.2" See gh-43531 --- .github/actions/publish-gradle-plugin/action.yml | 2 +- .github/actions/sync-to-maven-central/action.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/publish-gradle-plugin/action.yml b/.github/actions/publish-gradle-plugin/action.yml index 22fdbb3c7a80..790500f9dac7 100644 --- a/.github/actions/publish-gradle-plugin/action.yml +++ b/.github/actions/publish-gradle-plugin/action.yml @@ -21,7 +21,7 @@ runs: using: composite steps: - name: Set Up JFrog CLI - uses: jfrog/setup-jfrog-cli@040913fd7ac2a2bcb29a7e963ea99e7c309d63e5 # v4.5.0 + uses: jfrog/setup-jfrog-cli@dff217c085c17666e8849ebdbf29c8fe5e3995e6 # v4.5.2 env: JF_ENV_SPRING: ${{ inputs.jfrog-cli-config-token }} - name: Download Artifacts diff --git a/.github/actions/sync-to-maven-central/action.yml b/.github/actions/sync-to-maven-central/action.yml index 5acccb937998..0b4f35efef5c 100644 --- a/.github/actions/sync-to-maven-central/action.yml +++ b/.github/actions/sync-to-maven-central/action.yml @@ -20,7 +20,7 @@ runs: using: composite steps: - name: Set Up JFrog CLI - uses: jfrog/setup-jfrog-cli@040913fd7ac2a2bcb29a7e963ea99e7c309d63e5 # v4.5.0 + uses: jfrog/setup-jfrog-cli@dff217c085c17666e8849ebdbf29c8fe5e3995e6 # v4.5.2 env: JF_ENV_SPRING: ${{ inputs.jfrog-cli-config-token }} - name: Download Release Artifacts From 13c9f68b452c49e9d4bf2a75e2fcf764f6ae578f Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 17 Dec 2024 10:40:17 +0000 Subject: [PATCH 178/203] Upgrade to Dependency Management Plugin 1.1.7 Closes gh-43542 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index c507710415b3..5c31b488c7b9 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -290,7 +290,7 @@ bom { ] } } - library("Dependency Management Plugin", "1.1.6") { + library("Dependency Management Plugin", "1.1.7") { group("io.spring.gradle") { modules = [ "dependency-management-plugin" From a84e65f29d3c5db51495a6f3bfffe735000191c4 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 17 Dec 2024 10:42:27 +0000 Subject: [PATCH 179/203] Upgrade to Dependency Management Plugin 1.1.7 Closes gh-43543 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index ab211fa253d5..2be01456de67 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -290,7 +290,7 @@ bom { ] } } - library("Dependency Management Plugin", "1.1.6") { + library("Dependency Management Plugin", "1.1.7") { group("io.spring.gradle") { modules = [ "dependency-management-plugin" From 4763123932435d463e99e9375e5c2f47e0e0ae16 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Dec 2024 11:10:53 +0000 Subject: [PATCH 180/203] Recommend using Maven's Closes gh-43329 --- .../developing-auto-configuration.adoc | 25 ++++---------- .../annotation-processor.adoc | 33 ++++++++++++------- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/developing-auto-configuration.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/developing-auto-configuration.adoc index 07885f8e5018..f2d4a9592abf 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/developing-auto-configuration.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/developing-auto-configuration.adoc @@ -283,18 +283,7 @@ If you do it that way, the library is not provided and, by default, Spring Boot Spring Boot uses an annotation processor to collect the conditions on auto-configurations in a metadata file (`META-INF/spring-autoconfigure-metadata.properties`). If that file is present, it is used to eagerly filter auto-configurations that do not match, which will improve startup time. -When building with Maven, it is recommended to add the following dependency in a module that contains auto-configurations: - -[source,xml] ----- - - org.springframework.boot - spring-boot-autoconfigure-processor - true - ----- - -If you have defined auto-configurations directly in your application, make sure to configure the `spring-boot-maven-plugin` to prevent the `repackage` goal from adding the dependency into the uber jar: +When building with Maven, configure the compiler plugin (3.12.0 or later) to add `spring-boot-autoconfigure-processor` to the annotation processor paths: [source,xml] ---- @@ -302,15 +291,15 @@ If you have defined auto-configurations directly in your application, make sure - org.springframework.boot - spring-boot-maven-plugin + org.apache.maven.plugins + maven-compiler-plugin - - + + org.springframework.boot spring-boot-autoconfigure-processor - - + + diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/specification/pages/configuration-metadata/annotation-processor.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/specification/pages/configuration-metadata/annotation-processor.adoc index 9e2f80f33bbb..02ff8371349a 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/specification/pages/configuration-metadata/annotation-processor.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/specification/pages/configuration-metadata/annotation-processor.adoc @@ -9,20 +9,31 @@ The jar includes a Java annotation processor which is invoked as your project is [[appendix.configuration-metadata.annotation-processor.configuring]] == Configuring the Annotation Processor -To use the processor, include a dependency on `spring-boot-configuration-processor`. - -With Maven the dependency should be declared as optional, as shown in the following example: +When building with Maven, configure the compiler plugin (3.12.0 or later) to add `spring-boot-configuration-processor` to the annotation processor paths: [source,xml] ---- - - org.springframework.boot - spring-boot-configuration-processor - true - + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + org.springframework.boot + spring-boot-configuration-processor + + + + + + + ---- -With Gradle, the dependency should be declared in the `annotationProcessor` configuration, as shown in the following example: +With Gradle, a dependency should be declared in the `annotationProcessor` configuration, as shown in the following example: [source,gradle] ---- @@ -64,8 +75,8 @@ You could also let the AspectJ plugin run all the processing and disable annotat [NOTE] ==== If you are using Lombok in your project, you need to make sure that its annotation processor runs before `spring-boot-configuration-processor`. -To do so with Maven, you can list the annotation processors in the right order using the `annotationProcessors` attribute of the Maven compiler plugin. -If you are not using this attribute, and annotation processors are picked up by the dependencies available on the classpath, make sure that the `lombok` dependency is defined before the `spring-boot-configuration-processor` dependency. +To do so with Maven, list the annotation processors in the required order using the `annotationProcessors` attribute of the Maven compiler plugin. +With Gradle, declare the dependencies in the `annotationProcessor` configuration in the required order. ==== From 495665aec0cd5cbf27d1c0fdb3563669312122c2 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 17 Dec 2024 09:49:57 -0800 Subject: [PATCH 181/203] Use reverse order for shutdown hooks Refine `SpringApplicationShutdownHook` so that shutdown happens in reverse order to registration. See gh-43430 --- .../boot/SpringApplicationShutdownHook.java | 7 +++++-- .../boot/SpringApplicationShutdownHookTests.java | 6 +++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplicationShutdownHook.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplicationShutdownHook.java index 8e5e4ad3a349..433087a1bed9 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplicationShutdownHook.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplicationShutdownHook.java @@ -16,8 +16,10 @@ package org.springframework.boot; +import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashSet; +import java.util.List; import java.util.Set; import java.util.WeakHashMap; import java.util.concurrent.TimeUnit; @@ -103,12 +105,13 @@ void deregisterFailedApplicationContext(ConfigurableApplicationContext applicati public void run() { Set contexts; Set closedContexts; - Set handlers; + List handlers; synchronized (SpringApplicationShutdownHook.class) { this.inProgress = true; contexts = new LinkedHashSet<>(this.contexts); closedContexts = new LinkedHashSet<>(this.closedContexts); - handlers = new LinkedHashSet<>(this.handlers.getActions()); + handlers = new ArrayList<>(this.handlers.getActions()); + Collections.reverse(handlers); } contexts.forEach(this::closeAndWait); closedContexts.forEach(this::closeAndWait); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationShutdownHookTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationShutdownHookTests.java index 4d4d56947d7b..b1854e253198 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationShutdownHookTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationShutdownHookTests.java @@ -207,7 +207,7 @@ void deregistersFailedContext() { } @Test - void handlersRunInDeterministicOrder() { + void handlersRunInDeterministicOrderFromLastRegisteredToFirst() { TestSpringApplicationShutdownHook shutdownHook = new TestSpringApplicationShutdownHook(); Runnable r1 = mock(Runnable.class); Runnable r2 = mock(Runnable.class); @@ -217,9 +217,9 @@ void handlersRunInDeterministicOrder() { shutdownHook.getHandlers().add(r3); shutdownHook.run(); InOrder ordered = inOrder(r1, r2, r3); - ordered.verify(r2).run(); - ordered.verify(r1).run(); ordered.verify(r3).run(); + ordered.verify(r1).run(); + ordered.verify(r2).run(); ordered.verifyNoMoreInteractions(); } From f6875704c49968c46571262fcf5c3f6b6d6f8b04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Tue, 17 Dec 2024 21:15:04 +0100 Subject: [PATCH 182/203] Upgrade to Netty 4.1.116.Final Closes gh-43548 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 2be01456de67..def0d2b6a7ea 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -1580,7 +1580,7 @@ bom { releaseNotes("https://github.com/neo4j/neo4j-java-driver/releases/tag/{version}") } } - library("Netty", "4.1.115.Final") { + library("Netty", "4.1.116.Final") { group("io.netty") { imports = [ "netty-bom" From b1cb3b155ec4a7e96634322aeac991099e031c1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Tue, 17 Dec 2024 21:15:04 +0100 Subject: [PATCH 183/203] Upgrade to Spring Authorization Server 1.4.1 Closes gh-43412 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index def0d2b6a7ea..41c08b9fe247 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2098,7 +2098,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-amqp/releases/tag/v{version}") } } - library("Spring Authorization Server", "1.4.1-SNAPSHOT") { + library("Spring Authorization Server", "1.4.1") { considerSnapshots() group("org.springframework.security") { modules = [ From 6ffef13ead8eb6c190f6037cd47818ff6c754ddb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Tue, 17 Dec 2024 21:15:05 +0100 Subject: [PATCH 184/203] Upgrade to Spring Pulsar 1.2.1 Closes gh-43418 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 41c08b9fe247..3993aae9a62b 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2256,7 +2256,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-ldap/releases/tag/{version}") } } - library("Spring Pulsar", "1.2.1-SNAPSHOT") { + library("Spring Pulsar", "1.2.1") { considerSnapshots() group("org.springframework.pulsar") { imports = [ From 320f02a2c2914fa1662c521c076b4d4af6e74e98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Tue, 17 Dec 2024 21:15:14 +0100 Subject: [PATCH 185/203] Upgrade to Netty 4.1.116.Final Closes gh-43549 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 5c31b488c7b9..4e013a39fe1a 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -1559,7 +1559,7 @@ bom { releaseNotes("https://github.com/neo4j/neo4j-java-driver/releases/tag/{version}") } } - library("Netty", "4.1.115.Final") { + library("Netty", "4.1.116.Final") { group("io.netty") { imports = [ "netty-bom" From db93202534b44c345ef44b449c5f1e83034add8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Tue, 17 Dec 2024 21:15:15 +0100 Subject: [PATCH 186/203] Upgrade to Spring Authorization Server 1.3.4 Closes gh-43391 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 4e013a39fe1a..a5957b03b1c1 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2115,7 +2115,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-amqp/releases/tag/v{version}") } } - library("Spring Authorization Server", "1.3.4-SNAPSHOT") { + library("Spring Authorization Server", "1.3.4") { considerSnapshots() group("org.springframework.security") { modules = [ From 7b9701a47713ea921fe87d2c4829975b33cdcde5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Tue, 17 Dec 2024 21:15:15 +0100 Subject: [PATCH 187/203] Upgrade to Spring Integration 6.3.7 Closes gh-43476 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index a5957b03b1c1..5da7e8c65f40 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2218,7 +2218,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-hateoas/releases/tag/{version}") } } - library("Spring Integration", "6.3.7-SNAPSHOT") { + library("Spring Integration", "6.3.7") { considerSnapshots() group("org.springframework.integration") { imports = [ From a967a2fec052f34c5519960098112e50dfc30005 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Tue, 17 Dec 2024 21:15:15 +0100 Subject: [PATCH 188/203] Upgrade to Spring Pulsar 1.1.7 Closes gh-43396 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 5da7e8c65f40..7e24bece64c8 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2273,7 +2273,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-ldap/releases/tag/{version}") } } - library("Spring Pulsar", "1.1.7-SNAPSHOT") { + library("Spring Pulsar", "1.1.7") { considerSnapshots() group("org.springframework.pulsar") { imports = [ From cbb8d124c030068ca119706b3c363daf1bb0a2c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Tue, 17 Dec 2024 21:15:15 +0100 Subject: [PATCH 189/203] Upgrade to Spring Session 3.3.5 Closes gh-43397 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 7e24bece64c8..499599dc1a8b 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2337,7 +2337,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-security/releases/tag/{version}") } } - library("Spring Session", "3.3.5-SNAPSHOT") { + library("Spring Session", "3.3.5") { considerSnapshots() prohibit { startsWith(["Apple-", "Bean-", "Corn-", "Dragonfruit-"]) From aa374bf406b792c7662237736830bbff4e2ca8ed Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 17 Dec 2024 12:13:56 -0800 Subject: [PATCH 190/203] Correct links used in upgrade issues Update BOMR so that the `Upgrade` type now contains a copy of the library we're upgrading to complete with an updated version number. This allows the correct links to be generated. Closes gh-43545 --- .../boot/build/bom/Library.java | 11 ++- .../bom/bomr/InteractiveUpgradeResolver.java | 29 +++++--- .../boot/build/bom/bomr/MoveToSnapshots.java | 34 +-------- .../boot/build/bom/bomr/Upgrade.java | 29 ++++---- .../build/bom/bomr/UpgradeApplicator.java | 20 +++-- .../boot/build/bom/bomr/UpgradeBom.java | 28 ------- .../build/bom/bomr/UpgradeDependencies.java | 21 ++++-- .../bomr/InteractiveUpgradeResolverTests.java | 73 +++++++++++++++++++ .../boot/build/bom/bomr/UpgradeTests.java | 54 ++++++++++++++ 9 files changed, 198 insertions(+), 101 deletions(-) create mode 100644 buildSrc/src/test/java/org/springframework/boot/build/bom/bomr/InteractiveUpgradeResolverTests.java create mode 100644 buildSrc/src/test/java/org/springframework/boot/build/bom/bomr/UpgradeTests.java diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/Library.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/Library.java index 382c058630ab..5ab16ecdf822 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/bom/Library.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/Library.java @@ -101,7 +101,7 @@ public Library(String name, String calendarName, LibraryVersion version, List(links)); + this.links = (links != null) ? Collections.unmodifiableMap(new TreeMap<>(links)) : Collections.emptyMap(); } private static String generateLinkRootName(String name) { @@ -167,6 +167,15 @@ public List getLinks(String name) { return this.links.get(name); } + public String getNameAndVersion() { + return getName() + " " + getVersion(); + } + + public Library withVersion(LibraryVersion version) { + return new Library(this.name, this.calendarName, version, this.groups, this.prohibitedVersions, + this.considerSnapshots, this.versionAlignment, this.alignsWithBom, this.linkRootName, this.links); + } + /** * A version or range of versions that are prohibited from being used in a bom. */ diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/InteractiveUpgradeResolver.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/InteractiveUpgradeResolver.java index 532dfc972c2a..ac6515749f57 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/InteractiveUpgradeResolver.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/InteractiveUpgradeResolver.java @@ -51,10 +51,12 @@ public List resolveUpgrades(Collection librariesToUpgrade, Col for (Library library : libraries) { librariesByName.put(library.getName(), library); } - List libraryUpdates = this.libraryUpdateResolver - .findLibraryUpdates(librariesToUpgrade, librariesByName); try { - return libraryUpdates.stream().map(this::resolveUpgrade).filter(Objects::nonNull).toList(); + return this.libraryUpdateResolver.findLibraryUpdates(librariesToUpgrade, librariesByName) + .stream() + .map(this::resolveUpgrade) + .filter(Objects::nonNull) + .toList(); } catch (UpgradesInterruptedException ex) { return Collections.emptyList(); @@ -62,24 +64,29 @@ public List resolveUpgrades(Collection librariesToUpgrade, Col } private Upgrade resolveUpgrade(LibraryWithVersionOptions libraryWithVersionOptions) { - if (libraryWithVersionOptions.getVersionOptions().isEmpty()) { + Library library = libraryWithVersionOptions.getLibrary(); + List versionOptions = libraryWithVersionOptions.getVersionOptions(); + if (versionOptions.isEmpty()) { return null; } - VersionOption defaultOption = new VersionOption( - libraryWithVersionOptions.getLibrary().getVersion().getVersion()); + VersionOption defaultOption = new VersionOption(library.getVersion().getVersion()); + VersionOption selected = selectOption(defaultOption, library, versionOptions); + return (selected.equals(defaultOption)) ? null : new Upgrade(library, selected.getVersion()); + } + + private VersionOption selectOption(VersionOption defaultOption, Library library, + List versionOptions) { VersionOption selected = this.userInputHandler.askUser((questions) -> { - String question = libraryWithVersionOptions.getLibrary().getName() + " " - + libraryWithVersionOptions.getLibrary().getVersion().getVersion(); + String question = library.getNameAndVersion(); List options = new ArrayList<>(); options.add(defaultOption); - options.addAll(libraryWithVersionOptions.getVersionOptions()); + options.addAll(versionOptions); return questions.selectOption(question, options, defaultOption); }).get(); if (this.userInputHandler.interrupted()) { throw new UpgradesInterruptedException(); } - return (selected.equals(defaultOption)) ? null - : new Upgrade(libraryWithVersionOptions.getLibrary(), selected.getVersion()); + return selected; } static class UpgradesInterruptedException extends RuntimeException { diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/MoveToSnapshots.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/MoveToSnapshots.java index f04759873111..a4147a74ee52 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/MoveToSnapshots.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/MoveToSnapshots.java @@ -17,7 +17,6 @@ package org.springframework.boot.build.bom.bomr; import java.time.OffsetDateTime; -import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.function.BiPredicate; @@ -33,7 +32,6 @@ import org.springframework.boot.build.bom.BomExtension; import org.springframework.boot.build.bom.Library; import org.springframework.boot.build.bom.bomr.ReleaseSchedule.Release; -import org.springframework.boot.build.bom.bomr.github.Issue; import org.springframework.boot.build.bom.bomr.github.Milestone; import org.springframework.boot.build.bom.bomr.version.DependencyVersion; import org.springframework.boot.build.properties.BuildProperties; @@ -67,38 +65,10 @@ void upgradeDependencies() { super.upgradeDependencies(); } - @Override - protected String issueTitle(Upgrade upgrade) { - return "Upgrade to " + description(upgrade); - } - - private String description(Upgrade upgrade) { - String snapshotVersion = upgrade.getVersion().toString(); - String releaseVersion = snapshotVersion.substring(0, snapshotVersion.length() - "-SNAPSHOT".length()); - return upgrade.getLibrary().getName() + " " + releaseVersion; - } - - @Override - protected String issueBody(Upgrade upgrade, Issue existingUpgrade) { - Library library = upgrade.getLibrary(); - String releaseNotesLink = library.getLinkUrl("releaseNotes"); - List lines = new ArrayList<>(); - String description = description(upgrade); - if (releaseNotesLink != null) { - lines.add("Upgrade to [%s](%s).".formatted(description, releaseNotesLink)); - } - else { - lines.add("Upgrade to %s.".formatted(description)); - } - if (existingUpgrade != null) { - lines.add("Supersedes #" + existingUpgrade.getNumber()); - } - return String.join("\n\n", lines); - } - @Override protected String commitMessage(Upgrade upgrade, int issueNumber) { - return "Start building against " + description(upgrade) + " snapshots" + "\n\nSee gh-" + issueNumber; + return "Start building against " + upgrade.toRelease().getNameAndVersion() + " snapshots" + "\n\nSee gh-" + + issueNumber; } @Override diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/Upgrade.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/Upgrade.java index a7778d55264d..4ce6a8cfbefd 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/Upgrade.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/Upgrade.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2024 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. @@ -17,30 +17,33 @@ package org.springframework.boot.build.bom.bomr; import org.springframework.boot.build.bom.Library; +import org.springframework.boot.build.bom.Library.LibraryVersion; import org.springframework.boot.build.bom.bomr.version.DependencyVersion; /** * An upgrade to change a {@link Library} to use a new version. * * @author Andy Wilkinson + * @author Phillip Webb + * @param from the library we're upgrading from + * @param to the library we're upgrading to (may be a SNAPSHOT) + * @param toRelease the release version of the library we're ultimately upgrading to */ -final class Upgrade { +record Upgrade(Library from, Library to, Library toRelease) { - private final Library library; - - private final DependencyVersion version; - - Upgrade(Library library, DependencyVersion version) { - this.library = library; - this.version = version; + Upgrade(Library from, DependencyVersion to) { + this(from, from.withVersion(new LibraryVersion(to))); } - Library getLibrary() { - return this.library; + Upgrade(Library from, Library to) { + this(from, to, withReleaseVersion(to)); } - DependencyVersion getVersion() { - return this.version; + private static Library withReleaseVersion(Library to) { + String version = to.getVersion().toString(); + version = version.replace(".BUILD-SNAPSHOT", ""); + version = version.replace("-SNAPSHOT", ""); + return to.withVersion(new LibraryVersion(DependencyVersion.parse(version))); } } diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/UpgradeApplicator.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/UpgradeApplicator.java index 71d8872e4b96..7f818839157e 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/UpgradeApplicator.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/UpgradeApplicator.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -42,16 +42,14 @@ class UpgradeApplicator { Path apply(Upgrade upgrade) throws IOException { String buildFileContents = Files.readString(this.buildFile); - Matcher matcher = Pattern.compile("library\\(\"" + upgrade.getLibrary().getName() + "\", \"(.+)\"\\)") - .matcher(buildFileContents); + String toName = upgrade.to().getName(); + Matcher matcher = Pattern.compile("library\\(\"" + toName + "\", \"(.+)\"\\)").matcher(buildFileContents); if (!matcher.find()) { - matcher = Pattern - .compile("library\\(\"" + upgrade.getLibrary().getName() + "\"\\) \\{\\s+version\\(\"(.+)\"\\)", - Pattern.MULTILINE) + matcher = Pattern.compile("library\\(\"" + toName + "\"\\) \\{\\s+version\\(\"(.+)\"\\)", Pattern.MULTILINE) .matcher(buildFileContents); if (!matcher.find()) { - throw new IllegalStateException("Failed to find definition for library '" - + upgrade.getLibrary().getName() + "' in bom '" + this.buildFile + "'"); + throw new IllegalStateException("Failed to find definition for library '" + upgrade.to().getName() + + "' in bom '" + this.buildFile + "'"); } } String version = matcher.group(1); @@ -68,14 +66,14 @@ Path apply(Upgrade upgrade) throws IOException { private void updateGradleProperties(Upgrade upgrade, String version) throws IOException { String property = version.substring(2, version.length() - 1); String gradlePropertiesContents = Files.readString(this.gradleProperties); - String modified = gradlePropertiesContents.replace( - property + "=" + upgrade.getLibrary().getVersion().getVersion(), property + "=" + upgrade.getVersion()); + String modified = gradlePropertiesContents.replace(property + "=" + upgrade.from().getVersion(), + property + "=" + upgrade.to().getVersion()); overwrite(this.gradleProperties, modified); } private void updateBuildFile(Upgrade upgrade, String buildFileContents, int versionStart, int versionEnd) throws IOException { - String modified = buildFileContents.substring(0, versionStart) + upgrade.getVersion() + String modified = buildFileContents.substring(0, versionStart) + upgrade.to().getVersion() + buildFileContents.substring(versionEnd); overwrite(this.buildFile, modified); } diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/UpgradeBom.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/UpgradeBom.java index b78628629d63..c6d486e728d6 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/UpgradeBom.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/UpgradeBom.java @@ -16,9 +16,6 @@ package org.springframework.boot.build.bom.bomr; -import java.util.ArrayList; -import java.util.List; - import javax.inject.Inject; import org.gradle.api.Task; @@ -27,8 +24,6 @@ import org.gradle.api.artifacts.repositories.MavenArtifactRepository; import org.springframework.boot.build.bom.BomExtension; -import org.springframework.boot.build.bom.Library.LibraryVersion; -import org.springframework.boot.build.bom.bomr.github.Issue; import org.springframework.boot.build.properties.BuildProperties; /** @@ -63,32 +58,9 @@ private void addCommercialRepositories() { "spring-commercial-release"); } - @Override - protected String issueTitle(Upgrade upgrade) { - return "Upgrade to " + upgrade.getLibrary().getName() + " " + upgrade.getVersion(); - } - @Override protected String commitMessage(Upgrade upgrade, int issueNumber) { return issueTitle(upgrade) + "\n\nCloses gh-" + issueNumber; } - @Override - protected String issueBody(Upgrade upgrade, Issue existingUpgrade) { - LibraryVersion upgradeVersion = new LibraryVersion(upgrade.getVersion()); - String releaseNotesLink = upgrade.getLibrary().getLinkUrl("releaseNotes"); - List lines = new ArrayList<>(); - String description = upgrade.getLibrary().getName() + " " + upgradeVersion; - if (releaseNotesLink != null) { - lines.add("Upgrade to [%s](%s).".formatted(description, releaseNotesLink)); - } - else { - lines.add("Upgrade to %s.".formatted(description)); - } - if (existingUpgrade != null) { - lines.add("Supersedes #" + existingUpgrade.getNumber()); - } - return String.join("\n\n", lines); - } - } diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/UpgradeDependencies.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/UpgradeDependencies.java index 5d236b2e1fbc..713a6b51e0de 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/UpgradeDependencies.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/UpgradeDependencies.java @@ -118,7 +118,7 @@ private void applyUpgrades(GitHubRepository repository, List issueLabels System.out.println("Applying upgrades..."); System.out.println(""); for (Upgrade upgrade : upgrades) { - System.out.println(upgrade.getLibrary().getName() + " " + upgrade.getVersion()); + System.out.println(upgrade.to().getNameAndVersion()); Issue existingUpgradeIssue = findExistingUpgradeIssue(existingUpgradeIssues, upgrade); try { Path modified = this.upgradeApplicator.apply(upgrade); @@ -207,7 +207,7 @@ private Milestone determineMilestone(GitHubRepository repository) { } private Issue findExistingUpgradeIssue(List existingUpgradeIssues, Upgrade upgrade) { - String toMatch = "Upgrade to " + upgrade.getLibrary().getName(); + String toMatch = "Upgrade to " + upgrade.toRelease().getName(); for (Issue existingUpgradeIssue : existingUpgradeIssues) { String title = existingUpgradeIssue.getTitle(); int lastSpaceIndex = title.lastIndexOf(' '); @@ -285,10 +285,21 @@ protected boolean eligible(Library library) { return libraryPredicate.test(library.getName()); } - protected abstract String issueTitle(Upgrade upgrade); - protected abstract String commitMessage(Upgrade upgrade, int issueNumber); - protected abstract String issueBody(Upgrade upgrade, Issue existingUpgrade); + protected String issueTitle(Upgrade upgrade) { + return "Upgrade to " + upgrade.toRelease().getNameAndVersion(); + } + + protected String issueBody(Upgrade upgrade, Issue existingUpgrade) { + String description = upgrade.toRelease().getNameAndVersion(); + String releaseNotesLink = upgrade.toRelease().getLinkUrl("releaseNotes"); + String body = (releaseNotesLink != null) ? "Upgrade to [%s](%s).".formatted(description, releaseNotesLink) + : "Upgrade to %s.".formatted(description); + if (existingUpgrade != null) { + body += "\n\nSupersedes #" + existingUpgrade.getNumber(); + } + return body; + } } diff --git a/buildSrc/src/test/java/org/springframework/boot/build/bom/bomr/InteractiveUpgradeResolverTests.java b/buildSrc/src/test/java/org/springframework/boot/build/bom/bomr/InteractiveUpgradeResolverTests.java new file mode 100644 index 000000000000..25ba712301a5 --- /dev/null +++ b/buildSrc/src/test/java/org/springframework/boot/build/bom/bomr/InteractiveUpgradeResolverTests.java @@ -0,0 +1,73 @@ +/* + * Copyright 2024-2024 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.build.bom.bomr; + +import java.util.ArrayList; +import java.util.List; + +import org.gradle.api.internal.tasks.userinput.UserInputHandler; +import org.gradle.api.provider.Provider; +import org.junit.jupiter.api.Test; + +import org.springframework.boot.build.bom.Library; +import org.springframework.boot.build.bom.Library.LibraryVersion; +import org.springframework.boot.build.bom.bomr.version.DependencyVersion; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link InteractiveUpgradeResolver}. + * + * @author Phillip Webb + */ +class InteractiveUpgradeResolverTests { + + @Test + void resolveUpgradeUpdateVersionNumberInLibrary() { + UserInputHandler userInputHandler = mock(UserInputHandler.class); + LibraryUpdateResolver libaryUpdateResolver = mock(LibraryUpdateResolver.class); + InteractiveUpgradeResolver upgradeResolver = new InteractiveUpgradeResolver(userInputHandler, + libaryUpdateResolver); + List libraries = new ArrayList<>(); + DependencyVersion version = DependencyVersion.parse("1.0.0"); + LibraryVersion libraryVersion = new LibraryVersion(version); + Library library = new Library("test", null, libraryVersion, null, null, false, null, null, null, null); + libraries.add(library); + List librariesToUpgrade = new ArrayList<>(); + librariesToUpgrade.add(library); + List updates = new ArrayList<>(); + DependencyVersion updateVersion = DependencyVersion.parse("1.0.1"); + VersionOption versionOption = new VersionOption(updateVersion); + updates.add(new LibraryWithVersionOptions(library, List.of(versionOption))); + given(libaryUpdateResolver.findLibraryUpdates(any(), any())).willReturn(updates); + Provider providerOfVersionOption = providerOf(versionOption); + given(userInputHandler.askUser(any())).willReturn(providerOfVersionOption); + List upgrades = upgradeResolver.resolveUpgrades(librariesToUpgrade, libraries); + assertThat(upgrades.get(0).to().getVersion().getVersion()).isEqualTo(updateVersion); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + private Provider providerOf(VersionOption versionOption) { + Provider provider = mock(Provider.class); + given(provider.get()).willReturn(versionOption); + return provider; + } + +} diff --git a/buildSrc/src/test/java/org/springframework/boot/build/bom/bomr/UpgradeTests.java b/buildSrc/src/test/java/org/springframework/boot/build/bom/bomr/UpgradeTests.java new file mode 100644 index 000000000000..ee7a0c3e9b47 --- /dev/null +++ b/buildSrc/src/test/java/org/springframework/boot/build/bom/bomr/UpgradeTests.java @@ -0,0 +1,54 @@ +/* + * Copyright 2024-2024 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.build.bom.bomr; + +import org.junit.jupiter.api.Test; + +import org.springframework.boot.build.bom.Library; +import org.springframework.boot.build.bom.Library.LibraryVersion; +import org.springframework.boot.build.bom.bomr.version.DependencyVersion; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link Upgrade}. + * + * @author Phillip Webb + */ +class UpgradeTests { + + @Test + void createToRelease() { + Library from = new Library("Test", null, new LibraryVersion(DependencyVersion.parse("1.0.0")), null, null, + false, null, null, null, null); + Upgrade upgrade = new Upgrade(from, DependencyVersion.parse("1.0.1")); + assertThat(upgrade.from().getNameAndVersion()).isEqualTo("Test 1.0.0"); + assertThat(upgrade.to().getNameAndVersion()).isEqualTo("Test 1.0.1"); + assertThat(upgrade.toRelease().getNameAndVersion()).isEqualTo("Test 1.0.1"); + } + + @Test + void createToSnapshot() { + Library from = new Library("Test", null, new LibraryVersion(DependencyVersion.parse("1.0.0")), null, null, + false, null, null, null, null); + Upgrade upgrade = new Upgrade(from, DependencyVersion.parse("1.0.1-SNAPSHOT")); + assertThat(upgrade.from().getNameAndVersion()).isEqualTo("Test 1.0.0"); + assertThat(upgrade.to().getNameAndVersion()).isEqualTo("Test 1.0.1-SNAPSHOT"); + assertThat(upgrade.toRelease().getNameAndVersion()).isEqualTo("Test 1.0.1"); + } + +} From 229137d2cd2d0a9558910d6c3707e96d2242be54 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 17 Dec 2024 17:34:20 -0800 Subject: [PATCH 191/203] Document certain server.ssl.properties are ignored when using a bundle Closes gh-43353 --- .../docs/antora/modules/how-to/pages/webserver.adoc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/how-to/pages/webserver.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/how-to/pages/webserver.adoc index df2d4bd96238..fff0b690400e 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/how-to/pages/webserver.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/how-to/pages/webserver.adoc @@ -208,7 +208,15 @@ server: bundle: "example" ---- -NOTE: The `server.ssl.bundle` property can not be combined with the discrete Java KeyStore or PEM property options under `server.ssl`. +[NOTE] +==== +The `server.ssl.bundle` property can not be combined with the discrete Java KeyStore or PEM property options under `server.ssl`. + +The configprop:server.ssl.ciphers[], configprop:server.ssl.enabled-protocols[], configprop:server.ssl.protocol[] properties are also ignored when using a bundle. +These properties should instead be defined using `spring.ssl.bundle...options` properties. +==== + + [[howto.webserver.configure-ssl.sni]] === Configure Server Name Indication From 38d96aabef94debe6ae5647802e61b9510d88a67 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 17 Dec 2024 18:03:00 -0800 Subject: [PATCH 192/203] Drop {*-javadoc} attribute prefixes when possible Update javadoc references to use package name lookups rather than `{*-javadoc}` attributes. MongoDB and Testcontainers cannot be migrated since they have split packages. Closes gh-43223 --- .../src/docs/antora/modules/how-to/pages/aot.adoc | 2 +- .../src/docs/antora/modules/how-to/pages/batch.adoc | 4 ++-- .../docs/antora/modules/how-to/pages/data-access.adoc | 4 ++-- .../antora/modules/reference/pages/data/nosql.adoc | 4 ++-- .../docs/antora/modules/reference/pages/data/sql.adoc | 10 +++++----- .../reference/pages/features/external-config.adoc | 6 +++--- .../reference/pages/features/spring-application.adoc | 4 ++-- .../antora/modules/reference/pages/io/caching.adoc | 2 +- .../antora/modules/reference/pages/io/rest-client.adoc | 2 +- .../antora/modules/reference/pages/messaging/amqp.adoc | 4 ++-- .../antora/modules/reference/pages/messaging/jms.adoc | 4 ++-- .../antora/modules/reference/pages/web/servlet.adoc | 4 ++-- 12 files changed, 25 insertions(+), 25 deletions(-) diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/how-to/pages/aot.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/how-to/pages/aot.adoc index 59283af1a3ee..9fd0d0a8382d 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/how-to/pages/aot.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/how-to/pages/aot.adoc @@ -9,7 +9,7 @@ This section addresses those questions. [[howto.aot.conditions]] == Conditions -Ahead-of-time processing optimizes the application and evaluates javadoc:{url-spring-framework-javadoc}/org.springframework.context.annotation.Conditional[format=annotation] annotations based on the environment at build time. +Ahead-of-time processing optimizes the application and evaluates javadoc:org.springframework.context.annotation.Conditional[format=annotation] annotations based on the environment at build time. xref:reference:features/profiles.adoc[Profiles] are implemented through conditions and are therefore affected, too. If you want beans that are created based on a condition in an ahead-of-time optimized application, you have to set up the environment when building the application. diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/how-to/pages/batch.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/how-to/pages/batch.adoc index 79a481165ad7..8b650f5522c3 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/how-to/pages/batch.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/how-to/pages/batch.adoc @@ -14,8 +14,8 @@ Spring Batch expects a single javadoc:javax.sql.DataSource[] by default. To have it use a javadoc:javax.sql.DataSource[] other than the application’s main javadoc:javax.sql.DataSource[], declare a javadoc:javax.sql.DataSource[] bean, annotating its javadoc:org.springframework.context.annotation.Bean[format=annotation] method with javadoc:org.springframework.boot.autoconfigure.batch.BatchDataSource[format=annotation]. If you do so and want two data sources, remember to mark the other one javadoc:org.springframework.context.annotation.Primary[format=annotation]. To take greater control, add javadoc:org.springframework.batch.core.configuration.annotation.EnableBatchProcessing[format=annotation] to one of your javadoc:org.springframework.context.annotation.Configuration[format=annotation] classes or extend javadoc:org.springframework.batch.core.configuration.support.DefaultBatchConfiguration[]. -See the API documentation of javadoc:{url-spring-batch-javadoc}/org.springframework.batch.core.configuration.annotation.EnableBatchProcessing[format=annotation] -and javadoc:{url-spring-batch-javadoc}/org.springframework.batch.core.configuration.support.DefaultBatchConfiguration[] for more details. +See the API documentation of javadoc:org.springframework.batch.core.configuration.annotation.EnableBatchProcessing[format=annotation] +and javadoc:org.springframework.batch.core.configuration.support.DefaultBatchConfiguration[] for more details. For more info about Spring Batch, see the {url-spring-batch-site}[Spring Batch project page]. diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/how-to/pages/data-access.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/how-to/pages/data-access.adoc index b2928342e9e6..9cbc563ef622 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/how-to/pages/data-access.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/how-to/pages/data-access.adoc @@ -370,8 +370,8 @@ Note that if you are using Spring Data REST, you must use the properties in the Spring Data REST can expose the javadoc:org.springframework.data.repository.Repository[] implementations as REST endpoints for you, provided Spring MVC has been enabled for the application. -Spring Boot exposes a set of useful properties (from the `spring.data.rest` namespace) that customize the javadoc:{url-spring-data-rest-javadoc}/org.springframework.data.rest.core.config.RepositoryRestConfiguration[]. -If you need to provide additional customization, you should use a javadoc:{url-spring-data-rest-javadoc}/org.springframework.data.rest.webmvc.config.RepositoryRestConfigurer[] bean. +Spring Boot exposes a set of useful properties (from the `spring.data.rest` namespace) that customize the javadoc:org.springframework.data.rest.core.config.RepositoryRestConfiguration[]. +If you need to provide additional customization, you should use a javadoc:org.springframework.data.rest.webmvc.config.RepositoryRestConfigurer[] bean. NOTE: If you do not specify any order on your custom javadoc:org.springframework.data.rest.webmvc.config.RepositoryRestConfigurer[], it runs after the one Spring Boot uses internally. If you need to specify an order, make sure it is higher than 0. diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/data/nosql.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/data/nosql.adoc index c4e8a9dcaa37..aa1a855b868b 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/data/nosql.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/data/nosql.adoc @@ -202,12 +202,12 @@ The auto-configuration configures this factory automatically if Netty is availab [[data.nosql.mongodb.template]] === MongoTemplate -{url-spring-data-mongodb-site}[Spring Data MongoDB] provides a javadoc:{url-spring-data-mongodb-javadoc}/org.springframework.data.mongodb.core.MongoTemplate[] class that is very similar in its design to Spring's javadoc:org.springframework.jdbc.core.JdbcTemplate[]. +{url-spring-data-mongodb-site}[Spring Data MongoDB] provides a javadoc:org.springframework.data.mongodb.core.MongoTemplate[] class that is very similar in its design to Spring's javadoc:org.springframework.jdbc.core.JdbcTemplate[]. As with javadoc:org.springframework.jdbc.core.JdbcTemplate[], Spring Boot auto-configures a bean for you to inject the template, as follows: include-code::MyBean[] -See the javadoc:{url-spring-data-mongodb-javadoc}/org.springframework.data.mongodb.core.MongoOperations[] API documentation for complete details. +See the javadoc:org.springframework.data.mongodb.core.MongoOperations[] API documentation for complete details. diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/data/sql.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/data/sql.adoc index 01f36930a80f..3d7a538e1142 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/data/sql.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/data/sql.adoc @@ -236,9 +236,9 @@ See the xref:how-to:data-access.adoc#howto.data-access.separate-entity-definitio JPA queries are created automatically from your method names. For example, a `CityRepository` interface might declare a `findAllByState(String state)` method to find all the cities in a given state. -For more complex queries, you can annotate your method with Spring Data's javadoc:{url-spring-data-jpa-javadoc}/org.springframework.data.jpa.repository.Query[] annotation. +For more complex queries, you can annotate your method with Spring Data's javadoc:org.springframework.data.jpa.repository.Query[] annotation. -Spring Data repositories usually extend from the javadoc:{url-spring-data-commons-javadoc}/org.springframework.data.repository.Repository[] or javadoc:{url-spring-data-commons-javadoc}/org.springframework.data.repository.CrudRepository[] interfaces. +Spring Data repositories usually extend from the javadoc:org.springframework.data.repository.Repository[] or javadoc:org.springframework.data.repository.CrudRepository[] interfaces. If you use auto-configuration, the xref:using/auto-configuration.adoc#using.auto-configuration.packages[auto-configuration packages] are searched for repositories. TIP: You can customize the locations to look for repositories using javadoc:org.springframework.data.jpa.repository.config.EnableJpaRepositories[format=annotation]. @@ -313,7 +313,7 @@ By default, the DDL execution (or validation) is deferred until the javadoc:org. [[data.sql.jpa-and-spring-data.open-entity-manager-in-view]] === Open EntityManager in View -If you are running a web application, Spring Boot by default registers javadoc:{url-spring-framework-javadoc}/org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor[] to apply the "`Open EntityManager in View`" pattern, to allow for lazy loading in web views. +If you are running a web application, Spring Boot by default registers javadoc:org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor[] to apply the "`Open EntityManager in View`" pattern, to allow for lazy loading in web views. If you do not want this behavior, you should set `spring.jpa.open-in-view` to `false` in your `application.properties`. @@ -541,9 +541,9 @@ https://spring.io/projects/spring-data-r2dbc[Spring Data R2DBC] repositories are Queries are created automatically from your method names. For example, a `CityRepository` interface might declare a `findAllByState(String state)` method to find all the cities in a given state. -For more complex queries, you can annotate your method with Spring Data's javadoc:{url-spring-data-r2dbc-javadoc}/org.springframework.data.r2dbc.repository.Query[format=annotation] annotation. +For more complex queries, you can annotate your method with Spring Data's javadoc:org.springframework.data.r2dbc.repository.Query[format=annotation] annotation. -Spring Data repositories usually extend from the javadoc:{url-spring-data-commons-javadoc}/org.springframework.data.repository.Repository[] or javadoc:{url-spring-data-commons-javadoc}/org.springframework.data.repository.CrudRepository[] interfaces. +Spring Data repositories usually extend from the javadoc:org.springframework.data.repository.Repository[] or javadoc:org.springframework.data.repository.CrudRepository[] interfaces. If you use auto-configuration, the xref:using/auto-configuration.adoc#using.auto-configuration.packages[auto-configuration packages] are searched for repositories. The following example shows a typical Spring Data repository interface definition: diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/external-config.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/external-config.adoc index 841a0db5fc74..6b68bd6a4dd7 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/external-config.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/external-config.adoc @@ -11,7 +11,7 @@ Later property sources can override the values defined in earlier ones. Sources are considered in the following order: . Default properties (specified by setting javadoc:org.springframework.boot.SpringApplication#setDefaultProperties(java.util.Map)[]). -. javadoc:{url-spring-framework-javadoc}/org.springframework.context.annotation.PropertySource[format=annotation] annotations on your javadoc:org.springframework.context.annotation.Configuration[format=annotation] classes. +. javadoc:org.springframework.context.annotation.PropertySource[format=annotation] annotations on your javadoc:org.springframework.context.annotation.Configuration[format=annotation] classes. Please note that such property sources are not added to the javadoc:org.springframework.core.env.Environment[] until the application context is being refreshed. This is too late to configure certain properties such as `+logging.*+` and `+spring.main.*+` which are read before refresh begins. . Config data (such as `application.properties` files). @@ -25,8 +25,8 @@ Sources are considered in the following order: . Command line arguments. . `properties` attribute on your tests. Available on javadoc:org.springframework.boot.test.context.SpringBootTest[format=annotation] and the xref:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-tests[test annotations for testing a particular slice of your application]. -. javadoc:{url-spring-framework-javadoc}/org.springframework.test.context.DynamicPropertySource[format=annotation] annotations in your tests. -. javadoc:{url-spring-framework-javadoc}/org.springframework.test.context.TestPropertySource[format=annotation] annotations on your tests. +. javadoc:org.springframework.test.context.DynamicPropertySource[format=annotation] annotations in your tests. +. javadoc:org.springframework.test.context.TestPropertySource[format=annotation] annotations on your tests. . xref:using/devtools.adoc#using.devtools.globalsettings[Devtools global settings properties] in the `$HOME/.config/spring-boot` directory when devtools is active. Config data files are considered in the following order: diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/spring-application.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/spring-application.adoc index 30e54e878b01..8013e9e08cc6 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/spring-application.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/spring-application.adoc @@ -237,7 +237,7 @@ You can get more guidance about xref:how-to:deployment/cloud.adoc#howto.deployme [[features.spring-application.application-events-and-listeners]] == Application Events and Listeners -In addition to the usual Spring Framework events, such as javadoc:{url-spring-framework-javadoc}/org.springframework.context.event.ContextRefreshedEvent[], a javadoc:org.springframework.boot.SpringApplication[] sends some additional application events. +In addition to the usual Spring Framework events, such as javadoc:org.springframework.context.event.ContextRefreshedEvent[], a javadoc:org.springframework.boot.SpringApplication[] sends some additional application events. [NOTE] ==== @@ -373,7 +373,7 @@ TIP: If you want to know on which HTTP port the application is running, get the During the application startup, the javadoc:org.springframework.boot.SpringApplication[] and the javadoc:org.springframework.context.ApplicationContext[] perform many tasks related to the application lifecycle, the beans lifecycle or even processing application events. -With javadoc:{url-spring-framework-javadoc}/org.springframework.core.metrics.ApplicationStartup[], Spring Framework {url-spring-framework-docs}/core/beans/context-introduction.html#context-functionality-startup[allows you to track the application startup sequence with javadoc:org.springframework.core.metrics.StartupStep[] objects]. +With javadoc:org.springframework.core.metrics.ApplicationStartup[], Spring Framework {url-spring-framework-docs}/core/beans/context-introduction.html#context-functionality-startup[allows you to track the application startup sequence with javadoc:org.springframework.core.metrics.StartupStep[] objects]. This data can be collected for profiling purposes, or just to have a better understanding of an application startup process. You can choose an javadoc:org.springframework.core.metrics.ApplicationStartup[] implementation when setting up the javadoc:org.springframework.boot.SpringApplication[] instance. diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/io/caching.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/io/caching.adoc index 47e7a5e6c4af..c2092e8b07b9 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/io/caching.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/io/caching.adoc @@ -36,7 +36,7 @@ TIP: It is also possible to transparently {url-spring-framework-docs}/integratio The cache abstraction does not provide an actual store and relies on abstraction materialized by the javadoc:org.springframework.cache.Cache[] and javadoc:org.springframework.cache.CacheManager[] interfaces. -If you have not defined a bean of type javadoc:org.springframework.cache.CacheManager[] or a javadoc:org.springframework.cache.interceptor.CacheResolver[] named `cacheResolver` (see javadoc:{url-spring-framework-javadoc}/org.springframework.cache.annotation.CachingConfigurer[]), Spring Boot tries to detect the following providers (in the indicated order): +If you have not defined a bean of type javadoc:org.springframework.cache.CacheManager[] or a javadoc:org.springframework.cache.interceptor.CacheResolver[] named `cacheResolver` (see javadoc:org.springframework.cache.annotation.CachingConfigurer[]), Spring Boot tries to detect the following providers (in the indicated order): . xref:io/caching.adoc#io.caching.provider.generic[] . xref:io/caching.adoc#io.caching.provider.jcache[] (EhCache 3, Hazelcast, Infinispan, and others) diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/io/rest-client.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/io/rest-client.adoc index 90bc6d55675d..5a3e6948bf79 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/io/rest-client.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/io/rest-client.adoc @@ -134,7 +134,7 @@ include-code::settings/MyService[] [[io.rest-client.resttemplate]] == RestTemplate -Spring Framework's javadoc:{url-spring-framework-javadoc}/org.springframework.web.client.RestTemplate[] class predates javadoc:org.springframework.web.client.RestClient[] and is the classic way that many applications use to call remote REST services. +Spring Framework's javadoc:org.springframework.web.client.RestTemplate[] class predates javadoc:org.springframework.web.client.RestClient[] and is the classic way that many applications use to call remote REST services. You might choose to use javadoc:org.springframework.web.client.RestTemplate[] when you have existing code that you don't want to migrate to javadoc:org.springframework.web.client.RestClient[], or because you're already familiar with the javadoc:org.springframework.web.client.RestTemplate[] API. Since javadoc:org.springframework.web.client.RestTemplate[] instances often need to be customized before being used, Spring Boot does not provide any single auto-configured javadoc:org.springframework.web.client.RestTemplate[] bean. diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/messaging/amqp.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/messaging/amqp.adoc index ac61d66415da..5890061b59e7 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/messaging/amqp.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/messaging/amqp.adoc @@ -56,7 +56,7 @@ Spring's javadoc:org.springframework.amqp.core.AmqpTemplate[] and javadoc:org.sp include-code::MyBean[] -NOTE: javadoc:{url-spring-amqp-javadoc}/org.springframework.amqp.rabbit.core.RabbitMessagingTemplate[] can be injected in a similar manner. +NOTE: javadoc:org.springframework.amqp.rabbit.core.RabbitMessagingTemplate[] can be injected in a similar manner. If a javadoc:org.springframework.amqp.support.converter.MessageConverter[] bean is defined, it is associated automatically to the auto-configured javadoc:org.springframework.amqp.core.AmqpTemplate[]. If necessary, any javadoc:org.springframework.amqp.core.Queue[] that is defined as a bean is automatically used to declare a corresponding queue on the RabbitMQ instance. @@ -110,7 +110,7 @@ The following sample component creates a listener endpoint on the `someQueue` qu include-code::MyBean[] -TIP: See javadoc:{url-spring-amqp-javadoc}/org.springframework.amqp.rabbit.annotation.EnableRabbit[format=annotation] for more details. +TIP: See javadoc:org.springframework.amqp.rabbit.annotation.EnableRabbit[format=annotation] for more details. If you need to create more javadoc:org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory[] instances or if you want to override the default, Spring Boot provides a javadoc:org.springframework.boot.autoconfigure.amqp.SimpleRabbitListenerContainerFactoryConfigurer[] and a javadoc:org.springframework.boot.autoconfigure.amqp.DirectRabbitListenerContainerFactoryConfigurer[] that you can use to initialize a javadoc:org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory[] and a javadoc:org.springframework.amqp.rabbit.config.DirectRabbitListenerContainerFactory[] with the same settings as the factories used by the auto-configuration. diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/messaging/jms.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/messaging/jms.adoc index 18d5ddf9cd2f..1e2558758713 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/messaging/jms.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/messaging/jms.adoc @@ -132,7 +132,7 @@ Spring's javadoc:org.springframework.jms.core.JmsTemplate[] is auto-configured, include-code::MyBean[] -NOTE: javadoc:{url-spring-framework-javadoc}/org.springframework.jms.core.JmsMessagingTemplate[] can be injected in a similar manner. +NOTE: javadoc:org.springframework.jms.core.JmsMessagingTemplate[] can be injected in a similar manner. If a javadoc:org.springframework.jms.support.destination.DestinationResolver[] or a javadoc:org.springframework.jms.support.converter.MessageConverter[] bean is defined, it is associated automatically to the auto-configured javadoc:org.springframework.jms.core.JmsTemplate[]. @@ -155,7 +155,7 @@ The following component creates a listener endpoint on the `someQueue` destinati include-code::MyBean[] -TIP: See the javadoc:{url-spring-framework-javadoc}/org.springframework.jms.annotation.EnableJms[format=annotation] API documentation for more details. +TIP: See the javadoc:org.springframework.jms.annotation.EnableJms[format=annotation] API documentation for more details. If you need to create more javadoc:org.springframework.jms.config.JmsListenerContainerFactory[] instances or if you want to override the default, Spring Boot provides a javadoc:org.springframework.boot.autoconfigure.jms.DefaultJmsListenerContainerFactoryConfigurer[] that you can use to initialize a javadoc:org.springframework.jms.config.DefaultJmsListenerContainerFactory[] with the same settings as the one that is auto-configured. diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/web/servlet.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/web/servlet.adoc index c0b0d0ab4c84..52917fdd185d 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/web/servlet.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/web/servlet.adoc @@ -110,7 +110,7 @@ This can be useful when you want to re-order or remove some of the converters th === MessageCodesResolver Spring MVC has a strategy for generating error codes for rendering error messages from binding errors: javadoc:org.springframework.validation.MessageCodesResolver[]. -If you set the configprop:spring.mvc.message-codes-resolver-format[] property `PREFIX_ERROR_CODE` or `POSTFIX_ERROR_CODE`, Spring Boot creates one for you (see the enumeration in javadoc:{url-spring-framework-javadoc}/org.springframework.validation.DefaultMessageCodesResolver#Format[]). +If you set the configprop:spring.mvc.message-codes-resolver-format[] property `PREFIX_ERROR_CODE` or `POSTFIX_ERROR_CODE`, Spring Boot creates one for you (see the enumeration in javadoc:org.springframework.validation.DefaultMessageCodesResolver#Format[]). @@ -171,7 +171,7 @@ spring: NOTE: Links to resources are rewritten in templates at runtime, thanks to a javadoc:org.springframework.web.servlet.resource.ResourceUrlEncodingFilter[] that is auto-configured for Thymeleaf and FreeMarker. You should manually declare this filter when using JSPs. -Other template engines are currently not automatically supported but can be with custom template macros/helpers and the use of the javadoc:{url-spring-framework-javadoc}/org.springframework.web.servlet.resource.ResourceUrlProvider[]. +Other template engines are currently not automatically supported but can be with custom template macros/helpers and the use of the javadoc:org.springframework.web.servlet.resource.ResourceUrlProvider[]. When loading resources dynamically with, for example, a JavaScript module loader, renaming files is not an option. That is why other strategies are also supported and can be combined. From 9a403d92d733a528971483dc2618f45db6c98d4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Wed, 18 Dec 2024 08:30:02 +0100 Subject: [PATCH 193/203] Upgrade to Spring Integration 6.4.1 Closes gh-43415 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 3993aae9a62b..28f7b6caaffa 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2201,7 +2201,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-hateoas/releases/tag/{version}") } } - library("Spring Integration", "6.4.1-SNAPSHOT") { + library("Spring Integration", "6.4.1") { considerSnapshots() group("org.springframework.integration") { imports = [ From 63202f818eab11503547371310d1fd4a09a3e474 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Wed, 18 Dec 2024 08:30:02 +0100 Subject: [PATCH 194/203] Upgrade to Spring Session 3.4.1 Closes gh-43420 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 28f7b6caaffa..076e9429848b 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2320,7 +2320,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-security/releases/tag/{version}") } } - library("Spring Session", "3.4.1-SNAPSHOT") { + library("Spring Session", "3.4.1") { considerSnapshots() prohibit { startsWith(["Apple-", "Bean-", "Corn-", "Dragonfruit-"]) From 6366511b59978160f6152207bd7956239a5a330f Mon Sep 17 00:00:00 2001 From: Yanming Zhou Date: Wed, 18 Dec 2024 15:59:14 +0800 Subject: [PATCH 195/203] Fix typo See gh-43557 --- .../src/docs/antora/modules/reference/pages/packaging/aot.adoc | 2 +- .../native-image/introducing-graalvm-native-images.adoc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/packaging/aot.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/packaging/aot.adoc index fa41102b96da..a2488c38c5d1 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/packaging/aot.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/packaging/aot.adoc @@ -30,6 +30,6 @@ It implies the following restrictions: * The classpath is fixed and fully defined at build time * The beans defined in your application cannot change at runtime, meaning: - The Spring javadoc:org.springframework.context.annotation.Profile[format=annotation] annotation and profile-specific configuration xref:how-to:aot.adoc#howto.aot.conditions[have limitations]. -- Properties that change if a bean is created are not supported (for example, javadoc:org.springframework.boot.autoconfigure.condition.ConditionalOnProperty[format=annotation] and `.enable` properties). +- Properties that change if a bean is created are not supported (for example, javadoc:org.springframework.boot.autoconfigure.condition.ConditionalOnProperty[format=annotation] and `.enabled` properties). To learn more about ahead-of-time processing, please see the xref:packaging/native-image/introducing-graalvm-native-images.adoc#packaging.native-image.introducing-graalvm-native-images.understanding-aot-processing[] section. diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/packaging/native-image/introducing-graalvm-native-images.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/packaging/native-image/introducing-graalvm-native-images.adoc index 55a1302f284c..ff0fb3a0a804 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/packaging/native-image/introducing-graalvm-native-images.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/packaging/native-image/introducing-graalvm-native-images.adoc @@ -49,7 +49,7 @@ A closed-world assumption implies, besides xref:packaging/native-image/introduci * The beans defined in your application cannot change at runtime, meaning: - The Spring javadoc:org.springframework.context.annotation.Profile[format=annotation] annotation and profile-specific configuration xref:how-to:aot.adoc#howto.aot.conditions[have limitations]. -- Properties that change if a bean is created are not supported (for example, javadoc:org.springframework.boot.autoconfigure.condition.ConditionalOnProperty[format=annotation] and `.enable` properties). +- Properties that change if a bean is created are not supported (for example, javadoc:org.springframework.boot.autoconfigure.condition.ConditionalOnProperty[format=annotation] and `.enabled` properties). When these restrictions are in place, it becomes possible for Spring to perform ahead-of-time processing during build-time and generate additional assets that GraalVM can use. A Spring AOT processed application will typically generate: From a5c2f0fc74f2968e670ad18d61c7ae6e7c61940e Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 17 Dec 2024 19:20:01 +0000 Subject: [PATCH 196/203] Improve diagnostics when config prop value conversion fails Closes gh-43378 Co-Authored-By: Phillip Webb --- ...rationPropertySourcesPropertyResolver.java | 10 ++++++- ...idConfigurationPropertyValueException.java | 6 ++++- ...nPropertySourcesPropertyResolverTests.java | 27 +++++++++++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesPropertyResolver.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesPropertyResolver.java index 9cb2d77b7364..e1940ad66f22 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesPropertyResolver.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesPropertyResolver.java @@ -16,6 +16,7 @@ package org.springframework.boot.context.properties.source; +import org.springframework.core.convert.ConversionFailedException; import org.springframework.core.env.AbstractPropertyResolver; import org.springframework.core.env.MutablePropertySources; import org.springframework.core.env.PropertySources; @@ -79,7 +80,14 @@ private T getProperty(String key, Class targetValueType, boolean resolveN if (resolveNestedPlaceholders && value instanceof String string) { value = resolveNestedPlaceholders(string); } - return convertValueIfNecessary(value, targetValueType); + try { + return convertValueIfNecessary(value, targetValueType); + } + catch (ConversionFailedException ex) { + Exception wrappedCause = new InvalidConfigurationPropertyValueException(key, value, + "Failed to convert to type " + ex.getTargetType(), ex.getCause()); + throw new ConversionFailedException(ex.getSourceType(), ex.getTargetType(), ex.getValue(), wrappedCause); + } } private Object findPropertyValue(String key) { diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/InvalidConfigurationPropertyValueException.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/InvalidConfigurationPropertyValueException.java index edba3777cabc..1bef986b34ef 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/InvalidConfigurationPropertyValueException.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/InvalidConfigurationPropertyValueException.java @@ -43,7 +43,11 @@ public class InvalidConfigurationPropertyValueException extends RuntimeException * returns are allowed. */ public InvalidConfigurationPropertyValueException(String name, Object value, String reason) { - super("Property " + name + " with value '" + value + "' is invalid: " + reason); + this(name, value, reason, null); + } + + InvalidConfigurationPropertyValueException(String name, Object value, String reason, Throwable cause) { + super("Property " + name + " with value '" + value + "' is invalid: " + reason, cause); Assert.notNull(name, "Name must not be null"); this.name = name; this.value = value; diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesPropertyResolverTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesPropertyResolverTests.java index 8032febc231e..4378789df4a9 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesPropertyResolverTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesPropertyResolverTests.java @@ -22,12 +22,15 @@ import org.junit.jupiter.api.Test; +import org.springframework.core.convert.ConversionFailedException; +import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.env.ConfigurablePropertyResolver; import org.springframework.core.env.MutablePropertySources; import org.springframework.core.env.StandardEnvironment; import org.springframework.mock.env.MockPropertySource; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; /** * Tests for {@link ConfigurationPropertySourcesPropertyResolver}. @@ -113,6 +116,30 @@ void getPropertyAsTypeWhenHasPlaceholder() { assertThat(environment.getProperty("v2", Integer.class)).isOne(); } + @Test + void throwsInvalidConfigurationPropertyValueExceptionWhenGetPropertyAsTypeFailsToConvert() { + ResolverEnvironment environment = new ResolverEnvironment(); + MockPropertySource propertySource = new MockPropertySource(); + propertySource.withProperty("v1", "one"); + propertySource.withProperty("v2", "${v1}"); + environment.getPropertySources().addFirst(propertySource); + assertThat(environment.getProperty("v2")).isEqualTo("one"); + assertThatExceptionOfType(ConversionFailedException.class) + .isThrownBy(() -> environment.getProperty("v2", Integer.class)) + .satisfies((ex) -> { + assertThat(ex.getValue()).isEqualTo("one"); + assertThat(ex.getSourceType()).isEqualTo(TypeDescriptor.valueOf(String.class)); + assertThat(ex.getTargetType()).isEqualTo(TypeDescriptor.valueOf(Integer.class)); + }) + .havingCause() + .satisfies((ex) -> { + InvalidConfigurationPropertyValueException invalidValueEx = (InvalidConfigurationPropertyValueException) ex; + assertThat(invalidValueEx.getName()).isEqualTo("v2"); + assertThat(invalidValueEx.getValue()).isEqualTo("one"); + assertThat(ex).cause().isInstanceOf(NumberFormatException.class); + }); + } + private CountingMockPropertySource createMockPropertySource(StandardEnvironment environment, boolean attach) { CountingMockPropertySource propertySource = new CountingMockPropertySource(); propertySource.withProperty("spring", "boot"); From ba916cb66e8f6879a4cf8a3c162a03183042c6f7 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 18 Dec 2024 10:30:59 -0800 Subject: [PATCH 197/203] Allow KafkaProperties to build properties with empty bundle name Update `KafkaProperties` so that properties can still be built when the bundle name has no text. Fixes gh-43561 --- .../autoconfigure/kafka/KafkaProperties.java | 82 ++++++++++--------- .../client/ClientsConfiguredCondition.java | 3 +- .../kafka/KafkaPropertiesTests.java | 14 ++++ ...usiveConfigurationPropertiesException.java | 20 ++++- 4 files changed, 77 insertions(+), 42 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaProperties.java index 5ee77cd66ed2..7352d8dfe244 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaProperties.java @@ -43,6 +43,7 @@ import org.springframework.kafka.listener.ContainerProperties.AckMode; import org.springframework.kafka.security.jaas.KafkaJaasLoginModuleInitializer; import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; import org.springframework.util.unit.DataSize; /** @@ -1427,60 +1428,67 @@ public Map buildProperties() { public Map buildProperties(SslBundles sslBundles) { validate(); - Properties properties = new Properties(); - if (getBundle() != null) { - properties.in(SslConfigs.SSL_ENGINE_FACTORY_CLASS_CONFIG) - .accept(SslBundleSslEngineFactory.class.getName()); - properties.in(SslBundle.class.getName()).accept(sslBundles.getBundle(getBundle())); - } - else { - PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); - map.from(this::getKeyPassword).to(properties.in(SslConfigs.SSL_KEY_PASSWORD_CONFIG)); - map.from(this::getKeyStoreCertificateChain) - .to(properties.in(SslConfigs.SSL_KEYSTORE_CERTIFICATE_CHAIN_CONFIG)); - map.from(this::getKeyStoreKey).to(properties.in(SslConfigs.SSL_KEYSTORE_KEY_CONFIG)); - map.from(this::getKeyStoreLocation) - .as(this::resourceToPath) - .to(properties.in(SslConfigs.SSL_KEYSTORE_LOCATION_CONFIG)); - map.from(this::getKeyStorePassword).to(properties.in(SslConfigs.SSL_KEYSTORE_PASSWORD_CONFIG)); - map.from(this::getKeyStoreType).to(properties.in(SslConfigs.SSL_KEYSTORE_TYPE_CONFIG)); - map.from(this::getTrustStoreCertificates) - .to(properties.in(SslConfigs.SSL_TRUSTSTORE_CERTIFICATES_CONFIG)); - map.from(this::getTrustStoreLocation) - .as(this::resourceToPath) - .to(properties.in(SslConfigs.SSL_TRUSTSTORE_LOCATION_CONFIG)); - map.from(this::getTrustStorePassword).to(properties.in(SslConfigs.SSL_TRUSTSTORE_PASSWORD_CONFIG)); - map.from(this::getTrustStoreType).to(properties.in(SslConfigs.SSL_TRUSTSTORE_TYPE_CONFIG)); - map.from(this::getProtocol).to(properties.in(SslConfigs.SSL_PROTOCOL_CONFIG)); + String bundleName = getBundle(); + if (StringUtils.hasText(bundleName)) { + return buildPropertiesForSslBundle(sslBundles, bundleName); } + Properties properties = new Properties(); + PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); + map.from(this::getKeyPassword).to(properties.in(SslConfigs.SSL_KEY_PASSWORD_CONFIG)); + map.from(this::getKeyStoreCertificateChain) + .to(properties.in(SslConfigs.SSL_KEYSTORE_CERTIFICATE_CHAIN_CONFIG)); + map.from(this::getKeyStoreKey).to(properties.in(SslConfigs.SSL_KEYSTORE_KEY_CONFIG)); + map.from(this::getKeyStoreLocation) + .as(this::resourceToPath) + .to(properties.in(SslConfigs.SSL_KEYSTORE_LOCATION_CONFIG)); + map.from(this::getKeyStorePassword).to(properties.in(SslConfigs.SSL_KEYSTORE_PASSWORD_CONFIG)); + map.from(this::getKeyStoreType).to(properties.in(SslConfigs.SSL_KEYSTORE_TYPE_CONFIG)); + map.from(this::getTrustStoreCertificates).to(properties.in(SslConfigs.SSL_TRUSTSTORE_CERTIFICATES_CONFIG)); + map.from(this::getTrustStoreLocation) + .as(this::resourceToPath) + .to(properties.in(SslConfigs.SSL_TRUSTSTORE_LOCATION_CONFIG)); + map.from(this::getTrustStorePassword).to(properties.in(SslConfigs.SSL_TRUSTSTORE_PASSWORD_CONFIG)); + map.from(this::getTrustStoreType).to(properties.in(SslConfigs.SSL_TRUSTSTORE_TYPE_CONFIG)); + map.from(this::getProtocol).to(properties.in(SslConfigs.SSL_PROTOCOL_CONFIG)); + return properties; + } + + private Map buildPropertiesForSslBundle(SslBundles sslBundles, String name) { + Properties properties = new Properties(); + properties.in(SslConfigs.SSL_ENGINE_FACTORY_CLASS_CONFIG).accept(SslBundleSslEngineFactory.class.getName()); + properties.in(SslBundle.class.getName()).accept(sslBundles.getBundle(name)); return properties; } private void validate() { - MutuallyExclusiveConfigurationPropertiesException.throwIfMultipleNonNullValuesIn((entries) -> { + MutuallyExclusiveConfigurationPropertiesException.throwIfMultipleMatchingValuesIn((entries) -> { entries.put("spring.kafka.ssl.key-store-key", getKeyStoreKey()); entries.put("spring.kafka.ssl.key-store-location", getKeyStoreLocation()); - }); - MutuallyExclusiveConfigurationPropertiesException.throwIfMultipleNonNullValuesIn((entries) -> { + }, this::hasValue); + MutuallyExclusiveConfigurationPropertiesException.throwIfMultipleMatchingValuesIn((entries) -> { entries.put("spring.kafka.ssl.trust-store-certificates", getTrustStoreCertificates()); entries.put("spring.kafka.ssl.trust-store-location", getTrustStoreLocation()); - }); - MutuallyExclusiveConfigurationPropertiesException.throwIfMultipleNonNullValuesIn((entries) -> { + }, this::hasValue); + MutuallyExclusiveConfigurationPropertiesException.throwIfMultipleMatchingValuesIn((entries) -> { entries.put("spring.kafka.ssl.bundle", getBundle()); entries.put("spring.kafka.ssl.key-store-key", getKeyStoreKey()); - }); - MutuallyExclusiveConfigurationPropertiesException.throwIfMultipleNonNullValuesIn((entries) -> { + }, this::hasValue); + MutuallyExclusiveConfigurationPropertiesException.throwIfMultipleMatchingValuesIn((entries) -> { entries.put("spring.kafka.ssl.bundle", getBundle()); entries.put("spring.kafka.ssl.key-store-location", getKeyStoreLocation()); - }); - MutuallyExclusiveConfigurationPropertiesException.throwIfMultipleNonNullValuesIn((entries) -> { + }, this::hasValue); + MutuallyExclusiveConfigurationPropertiesException.throwIfMultipleMatchingValuesIn((entries) -> { entries.put("spring.kafka.ssl.bundle", getBundle()); entries.put("spring.kafka.ssl.trust-store-certificates", getTrustStoreCertificates()); - }); - MutuallyExclusiveConfigurationPropertiesException.throwIfMultipleNonNullValuesIn((entries) -> { + }, this::hasValue); + MutuallyExclusiveConfigurationPropertiesException.throwIfMultipleMatchingValuesIn((entries) -> { entries.put("spring.kafka.ssl.bundle", getBundle()); entries.put("spring.kafka.ssl.trust-store-location", getTrustStoreLocation()); - }); + }, this::hasValue); + } + + private boolean hasValue(Object value) { + return (value instanceof String string) ? StringUtils.hasText(string) : value != null; } private String resourceToPath(Resource resource) { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/ClientsConfiguredCondition.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/ClientsConfiguredCondition.java index 43e7ef93f99c..d4d9df519ee2 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/ClientsConfiguredCondition.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/ClientsConfiguredCondition.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -36,7 +36,6 @@ * @author Madhura Bhave * @since 2.1.0 */ - public class ClientsConfiguredCondition extends SpringBootCondition { private static final Bindable> STRING_REGISTRATION_MAP = Bindable diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaPropertiesTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaPropertiesTests.java index f6d45dfd0a69..08fb63213aeb 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaPropertiesTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaPropertiesTests.java @@ -87,6 +87,20 @@ void sslPemConfiguration() { "-----BEGINchain"); } + @Test + void sslPemConfigurationWithEmptyBundle() { + KafkaProperties properties = new KafkaProperties(); + properties.getSsl().setKeyStoreKey("-----BEGINkey"); + properties.getSsl().setTrustStoreCertificates("-----BEGINtrust"); + properties.getSsl().setKeyStoreCertificateChain("-----BEGINchain"); + properties.getSsl().setBundle(""); + Map consumerProperties = properties.buildConsumerProperties(); + assertThat(consumerProperties).containsEntry(SslConfigs.SSL_KEYSTORE_KEY_CONFIG, "-----BEGINkey"); + assertThat(consumerProperties).containsEntry(SslConfigs.SSL_TRUSTSTORE_CERTIFICATES_CONFIG, "-----BEGINtrust"); + assertThat(consumerProperties).containsEntry(SslConfigs.SSL_KEYSTORE_CERTIFICATE_CHAIN_CONFIG, + "-----BEGINchain"); + } + @Test void sslBundleConfiguration() { KafkaProperties properties = new KafkaProperties(); diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/MutuallyExclusiveConfigurationPropertiesException.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/MutuallyExclusiveConfigurationPropertiesException.java index 3509489087cf..b0fa0a3e8167 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/MutuallyExclusiveConfigurationPropertiesException.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/MutuallyExclusiveConfigurationPropertiesException.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -20,8 +20,10 @@ import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.function.Consumer; +import java.util.function.Predicate; import java.util.stream.Collectors; import org.springframework.util.Assert; @@ -96,11 +98,23 @@ private static String buildMessage(Set mutuallyExclusiveNames, Set> entries) { - Map map = new LinkedHashMap<>(); + throwIfMultipleMatchingValuesIn(entries, Objects::nonNull); + } + + /** + * Throw a new {@link MutuallyExclusiveConfigurationPropertiesException} if multiple + * values are defined in a set of entries that match the given predicate. + * @param the value type + * @param entries a consumer used to populate the entries to check + * @param predicate the predicate used to check for matching values + * @since 3.3.7 + */ + public static void throwIfMultipleMatchingValuesIn(Consumer> entries, Predicate predicate) { + Map map = new LinkedHashMap<>(); entries.accept(map); Set configuredNames = map.entrySet() .stream() - .filter((entry) -> entry.getValue() != null) + .filter((entry) -> predicate.test(entry.getValue())) .map(Map.Entry::getKey) .collect(Collectors.toCollection(LinkedHashSet::new)); if (configuredNames.size() > 1) { From dbc1fc26e6fac03eab894599173a726fe5e098ac Mon Sep 17 00:00:00 2001 From: arefbehboudi Date: Wed, 18 Dec 2024 20:18:29 +0330 Subject: [PATCH 198/203] Polish See gh-43560 --- .../devtools/tests/JarFileRemoteApplicationLauncher.java | 5 ++--- .../boot/devtools/restart/RestartApplicationListener.java | 4 ++-- .../devtools/restart/classloader/RestartClassLoader.java | 4 ++-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/spring-boot-project/spring-boot-devtools/src/intTest/java/org/springframework/boot/devtools/tests/JarFileRemoteApplicationLauncher.java b/spring-boot-project/spring-boot-devtools/src/intTest/java/org/springframework/boot/devtools/tests/JarFileRemoteApplicationLauncher.java index 9cc7dee48cee..2af0ad2f4ba5 100644 --- a/spring-boot-project/spring-boot-devtools/src/intTest/java/org/springframework/boot/devtools/tests/JarFileRemoteApplicationLauncher.java +++ b/spring-boot-project/spring-boot-devtools/src/intTest/java/org/springframework/boot/devtools/tests/JarFileRemoteApplicationLauncher.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2024 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. @@ -55,8 +55,7 @@ protected String createApplicationClassPath() throws Exception { List entries = new ArrayList<>(); entries.add(appJar.getAbsolutePath()); entries.addAll(getDependencyJarPaths()); - String classpath = StringUtils.collectionToDelimitedString(entries, File.pathSeparator); - return classpath; + return StringUtils.collectionToDelimitedString(entries, File.pathSeparator); } private void addToJar(JarOutputStream output, File root, File current) throws IOException { diff --git a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/RestartApplicationListener.java b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/RestartApplicationListener.java index e42e095be386..5a5b0d9b05e6 100644 --- a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/RestartApplicationListener.java +++ b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/RestartApplicationListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -62,7 +62,7 @@ public void onApplicationEvent(ApplicationEvent event) { } private void onApplicationStartingEvent(ApplicationStartingEvent event) { - // It's too early to use the Spring environment but we should still allow + // It's too early to use the Spring environment, but we should still allow // users to disable restart using a System property. String enabled = System.getProperty(ENABLED_PROPERTY); RestartInitializer restartInitializer = null; diff --git a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/classloader/RestartClassLoader.java b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/classloader/RestartClassLoader.java index e988d88e251f..94f1a10143fd 100644 --- a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/classloader/RestartClassLoader.java +++ b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/classloader/RestartClassLoader.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2024 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. @@ -167,7 +167,7 @@ public boolean isClassReloadable(Class classType) { } /** - * Compound {@link Enumeration} that adds an additional item to the front. + * Compound {@link Enumeration} that adds an item to the front. */ private static class CompoundEnumeration implements Enumeration { From fcc569e5c4e381417d707873d6fc07afbd77a48a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Thu, 19 Dec 2024 06:42:19 +0100 Subject: [PATCH 199/203] Upgrade to Hibernate 6.6.4.Final Closes gh-43566 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 076e9429848b..465eb30e4067 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -514,7 +514,7 @@ bom { releaseNotes("https://github.com/hazelcast/hazelcast/releases/tag/v{version}") } } - library("Hibernate", "6.6.3.Final") { + library("Hibernate", "6.6.4.Final") { group("org.hibernate.orm") { modules = [ "hibernate-agroal", From a085a0111d1d12d09851bf4c951d03ffe52c6184 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Thu, 19 Dec 2024 06:42:24 +0100 Subject: [PATCH 200/203] Upgrade to Spring Batch 5.1.3 Closes gh-43474 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 499599dc1a8b..4c2306f3e391 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2132,7 +2132,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-authorization-server/releases/tag/{version}") } } - library("Spring Batch", "5.1.3-SNAPSHOT") { + library("Spring Batch", "5.1.3") { considerSnapshots() group("org.springframework.batch") { imports = [ From da593800be7828391944123dc45a6a705fc42701 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Thu, 19 Dec 2024 06:42:24 +0100 Subject: [PATCH 201/203] Upgrade to Spring Batch 5.2.1 Closes gh-43477 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 465eb30e4067..0975b5e52aab 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2115,7 +2115,7 @@ bom { releaseNotes("https://github.com/spring-projects/spring-authorization-server/releases/tag/{version}") } } - library("Spring Batch", "5.2.1-SNAPSHOT") { + library("Spring Batch", "5.2.1") { considerSnapshots() group("org.springframework.batch") { imports = [ From 316fe52df4cef90b6fffc850ecf8bd2c9e887846 Mon Sep 17 00:00:00 2001 From: Moritz Halbritter Date: Thu, 19 Dec 2024 12:10:05 +0100 Subject: [PATCH 202/203] Next development version (v3.3.8-SNAPSHOT) --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 1006a5e0eaf1..008dc10d707d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=3.3.7-SNAPSHOT +version=3.3.8-SNAPSHOT latestVersion=false spring.build-type=oss From 183285258d7b5092224eab1600a2cfa8332682d9 Mon Sep 17 00:00:00 2001 From: Moritz Halbritter Date: Thu, 19 Dec 2024 12:31:15 +0100 Subject: [PATCH 203/203] Release v3.4.1 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 0beda7f9910c..32cd596e3fa2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=3.4.1-SNAPSHOT +version=3.4.1 latestVersion=true spring.build-type=oss