From 2b7f6f3c6932a12e15d4eaed29592c73e661f944 Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Fri, 5 Jun 2026 12:50:49 -0700 Subject: [PATCH 01/10] Address new warnings from NullAway 0.13.6 Signed-off-by: Manu Sridharan See gh-50701 --- .../boot/test/context/assertj/ApplicationContextAssert.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/ApplicationContextAssert.java b/core/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/ApplicationContextAssert.java index 37f8e71175cb..6fca20b6852f 100644 --- a/core/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/ApplicationContextAssert.java +++ b/core/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/ApplicationContextAssert.java @@ -269,7 +269,7 @@ public AbstractObjectAssert getBean(Class type) { * @throws AssertionError if the application context contains multiple beans of the * given type */ - public AbstractObjectAssert getBean(Class type, Scope scope) { + public AbstractObjectAssert getBean(Class type, Scope scope) { Assert.notNull(scope, "'scope' must not be null"); if (this.startupFailure != null) { throwAssertionError( @@ -329,7 +329,7 @@ private boolean isPrimary(String name, Scope scope) { * is found * @throws AssertionError if the application context did not start */ - public AbstractObjectAssert getBean(String name) { + public AbstractObjectAssert getBean(String name) { if (this.startupFailure != null) { throwAssertionError( contextFailedToStartWhenExpecting(this.startupFailure, "to contain a bean of name:%n <%s>", name)); @@ -356,7 +356,7 @@ public AbstractObjectAssert getBean(String name) { * name but a different type */ @SuppressWarnings("unchecked") - public AbstractObjectAssert getBean(String name, Class type) { + public AbstractObjectAssert getBean(String name, Class type) { if (this.startupFailure != null) { throwAssertionError(contextFailedToStartWhenExpecting(this.startupFailure, "to contain a bean of name:%n <%s> (%s)", name, type)); From 8715efc615597511979de23617246e18d3e3b640 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 24 Jun 2026 13:16:40 +0100 Subject: [PATCH 02/10] Polish "Address new warnings from NullAway 0.13.6" See gh-50701 --- .../boot/test/context/assertj/ApplicationContextAssert.java | 2 +- gradle.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/ApplicationContextAssert.java b/core/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/ApplicationContextAssert.java index 6fca20b6852f..9e3ba932f74a 100644 --- a/core/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/ApplicationContextAssert.java +++ b/core/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/ApplicationContextAssert.java @@ -248,7 +248,7 @@ public AbstractObjectArrayAssert getBeanNames(Class type) { * @throws AssertionError if the application context contains multiple beans of the * given type */ - public AbstractObjectAssert getBean(Class type) { + public AbstractObjectAssert getBean(Class type) { return getBean(type, Scope.INCLUDE_ANCESTORS); } diff --git a/gradle.properties b/gradle.properties index 1fa1e034f254..05911ef98bcb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -19,7 +19,7 @@ kotlinVersion=2.2.21 mavenVersion=3.9.13 mockitoVersion=5.20.0 nativeBuildToolsVersion=0.11.5 -nullabilityPluginVersion=0.0.11 +nullabilityPluginVersion=0.0.14 snakeYamlVersion=2.5 springFrameworkVersion=7.0.8 springFramework60xVersion=6.0.23 From 0acd43d598236a0adb39d8d7f0011abce85c6290 Mon Sep 17 00:00:00 2001 From: Doehyun Baek Date: Sat, 20 Jun 2026 08:11:12 +0000 Subject: [PATCH 03/10] Update web starter documentation Signed-off-by: Doehyun Baek See gh-50842 --- .../src/docs/antora/modules/reference/pages/web/index.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/web/index.adoc b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/web/index.adoc index 4e0dc5592c06..552c321215a5 100644 --- a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/web/index.adoc +++ b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/web/index.adoc @@ -3,7 +3,7 @@ Spring Boot is well suited for web application development. You can create a self-contained HTTP server by using embedded Tomcat, Jetty, or Netty. -Most web applications use the `spring-boot-starter-web` module to get up and running quickly. +Most web applications use the `spring-boot-starter-webmvc` module to get up and running quickly. You can also choose to build reactive web applications by using the `spring-boot-starter-webflux` module. If you have not yet developed a Spring Boot web application, you can follow the "`Hello World!`" example in the xref:tutorial:first-application/index.adoc[Getting started] section. From 9a2fb471bd6c2d37f9e2835d1bad13d0d04c7376 Mon Sep 17 00:00:00 2001 From: Doehyun Baek Date: Fri, 12 Jun 2026 05:18:21 +0000 Subject: [PATCH 04/10] Fix forwarded headers property in cloud deployment docs Signed-off-by: Doehyun Baek See gh-50841 --- .../src/docs/antora/modules/how-to/pages/deployment/cloud.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/deployment/cloud.adoc b/documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/deployment/cloud.adoc index b6b093a5ecfc..be9d1104723a 100644 --- a/documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/deployment/cloud.adoc +++ b/documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/deployment/cloud.adoc @@ -24,7 +24,7 @@ In this section, we look at what it takes to get the xref:tutorial:first-applica Support for xref:how-to:webserver.adoc#howto.webserver.use-behind-a-proxy-server[forwarded headers] should only be enabled when the application receives traffic from a trusted HTTP proxy, and is only directly accessible from a trusted network. When running on a cloud platform, forward headers are enabled automatically. This builds on the assumption that the platform will ensure that individual application instances will only be directly accessible from a trusted network. -If that is not the case for your specific platform, set `spring.forward-headers-strategy` to `none`. +If that is not the case for your specific platform, set `server.forward-headers-strategy` to `none`. [[howto.deployment.cloud.cloud-foundry]] From 8f217b48a1ecfee925be432914504d812da3b4e0 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 24 Jun 2026 15:38:35 +0100 Subject: [PATCH 05/10] Polish "Fix forwarded headers property in cloud deployment docs" See gh-50841 --- .../src/docs/antora/modules/how-to/pages/deployment/cloud.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/deployment/cloud.adoc b/documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/deployment/cloud.adoc index be9d1104723a..7189b7382d33 100644 --- a/documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/deployment/cloud.adoc +++ b/documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/deployment/cloud.adoc @@ -24,7 +24,7 @@ In this section, we look at what it takes to get the xref:tutorial:first-applica Support for xref:how-to:webserver.adoc#howto.webserver.use-behind-a-proxy-server[forwarded headers] should only be enabled when the application receives traffic from a trusted HTTP proxy, and is only directly accessible from a trusted network. When running on a cloud platform, forward headers are enabled automatically. This builds on the assumption that the platform will ensure that individual application instances will only be directly accessible from a trusted network. -If that is not the case for your specific platform, set `server.forward-headers-strategy` to `none`. +If that is not the case for your specific platform, set configprop:server.forward-headers-strategy[] to `none`. [[howto.deployment.cloud.cloud-foundry]] From f7c2c0b2a691f5828f2cc07b28e723408737b507 Mon Sep 17 00:00:00 2001 From: Doehyun Baek Date: Sat, 20 Jun 2026 08:09:46 +0000 Subject: [PATCH 06/10] Align documentation with changes made during 4.1's development Signed-off-by: Doehyun Baek See gh-50800 --- .../src/docs/antora/modules/maven-plugin/pages/run.adoc | 2 -- .../src/docs/antora/modules/how-to/pages/hotswapping.adoc | 4 +--- .../antora/modules/reference/pages/features/dev-services.adoc | 2 +- .../docs/antora/modules/reference/pages/features/logging.adoc | 2 +- .../docs/antora/modules/reference/pages/security/oauth2.adoc | 4 ++-- .../reference/pages/testing/spring-boot-applications.adoc | 4 ++-- .../modules/reference/pages/testing/testcontainers.adoc | 2 +- .../oauth2/client/autoconfigure/OAuth2ClientProperties.java | 2 +- 8 files changed, 9 insertions(+), 13 deletions(-) diff --git a/build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/pages/run.adoc b/build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/pages/run.adoc index b06bf52fd78d..aa2eeb4b6a8c 100644 --- a/build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/pages/run.adoc +++ b/build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/pages/run.adoc @@ -26,8 +26,6 @@ include::example$running/devtools-pom.xml[tags=devtools] When `devtools` is running, it detects changes when you recompile your application and automatically refreshes it. This works for not only resources but code as well. -It also provides a LiveReload server so that it can automatically trigger a browser refresh whenever things change. - Devtools can also be configured to only refresh the browser whenever a static resource has changed (and ignore any change in the code). Just include the following property in your project: diff --git a/documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/hotswapping.adoc b/documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/hotswapping.adoc index 906e32e2ccb0..ce2e7437e39f 100644 --- a/documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/hotswapping.adoc +++ b/documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/hotswapping.adoc @@ -10,14 +10,12 @@ This section answers questions about how it works. == Reload Static Content There are several options for hot reloading. -The recommended approach is to use xref:reference:using/devtools.adoc[`spring-boot-devtools`], as it provides additional development-time features, such as support for fast application restarts and LiveReload as well as sensible development-time configuration (such as template caching). +The recommended approach is to use xref:reference:using/devtools.adoc[`spring-boot-devtools`], as it provides additional development-time features, such as support for fast application restarts as well as sensible development-time configuration (such as template caching). Devtools works by monitoring the classpath for changes. This means that static resource changes must be "built" for the change to take effect. By default, this happens automatically in Eclipse when you save your changes. In IntelliJ IDEA, the Make Project command triggers the necessary build. Due to the xref:reference:using/devtools.adoc#using.devtools.restart.excluding-resources[default restart exclusions], changes to static resources do not trigger a restart of your application. -They do, however, trigger a live reload. - Alternatively, running in an IDE (especially with debugging on) is a good way to do development (all modern IDEs allow reloading of static resources and usually also allow hot-swapping of Java class changes). Finally, the xref:build-tool-plugin:index.adoc[Maven and Gradle plugins] can be configured (see the `addResources` property) to support running from the command line with reloading of static files directly from source. diff --git a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/dev-services.adoc b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/dev-services.adoc index f18d9d9f9dec..f06dee89a7a4 100644 --- a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/dev-services.adoc +++ b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/dev-services.adoc @@ -129,7 +129,7 @@ The following service connections are currently supported: | Containers named "rabbitmq" with container port 5672 mapped | javadoc:org.springframework.boot.amqp.autoconfigure.RabbitStreamConnectionDetails[] -| Containers named "rabbitmq" with container port 5552 mapped +| Containers named "rabbitmq" with container port 5552 mapped, or port 5551 mapped when SSL is configured | javadoc:org.springframework.boot.data.redis.autoconfigure.DataRedisConnectionDetails[] | Containers named "redis", "redis/redis-stack" or "redis/redis-stack-server" diff --git a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/logging.adoc b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/logging.adoc index 53760e83f542..64676c943345 100644 --- a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/logging.adoc +++ b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/logging.adoc @@ -215,7 +215,7 @@ As a result, specific configuration keys (such as `logback.configurationFile` fo [[features.logging.file-rotation]] == File Rotation -If you are using Logback of Log4J2, it is possible to fine-tune log rotation settings using your `application.properties` or `application.yaml` file. +If you are using Logback or Log4j2, it is possible to fine-tune log rotation settings using your `application.properties` or `application.yaml` file. For all other logging system, you will need to configure rotation settings directly yourself. The following rotation policy properties are supported for Logback: diff --git a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/security/oauth2.adoc b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/security/oauth2.adoc index 143238d79443..524af65add5e 100644 --- a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/security/oauth2.adoc +++ b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/security/oauth2.adoc @@ -124,8 +124,8 @@ For production environments, consider using a javadoc:org.springframework.securi [[security.oauth2.client.common-providers]] === OAuth2 Client Registration for Common Providers -For common OAuth2 and OpenID providers (Google, Github, Facebook, and Okta), we provide a set of provider defaults. -The IDs of these common providers are `google`, `github`, `facebook`, and `okta`, respectively. +For common OAuth2 and OpenID providers (Google, Github, Facebook, X, and Okta), we provide a set of provider defaults. +The IDs of these common providers are `google`, `github`, `facebook`, `x`, and `okta`, respectively. If you do not need to customize these providers, set the registration's `provider` property to the ID of one of the common providers. Alternatively, you can xref:security/oauth2.adoc#security.oauth2.client[use a registration ID that matches the ID of the provider]. diff --git a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/spring-boot-applications.adoc b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/spring-boot-applications.adoc index 361e9eec4d4d..f5307e6757f6 100644 --- a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/spring-boot-applications.adoc +++ b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/spring-boot-applications.adoc @@ -740,11 +740,11 @@ TIP: A list of the auto-configuration settings that are enabled by javadoc:org.s The specific beans that you want to test should be specified by using the `value` or `components` attribute of javadoc:org.springframework.boot.restclient.test.autoconfigure.RestClientTest[format=annotation]. -When using a javadoc:org.springframework.boot.restclient.RestTemplateBuilder[] in the beans under test and `RestTemplateBuilder.rootUri(String rootUri)` has been called when building the javadoc:org.springframework.web.client.RestTemplate[], then the root URI should be omitted from the javadoc:org.springframework.test.web.client.MockRestServiceServer[] expectations as shown in the following example: +When using a javadoc:org.springframework.boot.restclient.RestTemplateBuilder[] in the beans under test and `RestTemplateBuilder.baseUri(String baseUri)` has been called when building the javadoc:org.springframework.web.client.RestTemplate[], then the base URI should be omitted from the javadoc:org.springframework.test.web.client.MockRestServiceServer[] expectations as shown in the following example: include-code::MyRestTemplateServiceTests[] -When using a javadoc:org.springframework.web.client.RestClient$Builder[] in the beans under test, or when using a javadoc:org.springframework.boot.restclient.RestTemplateBuilder[] without calling `rootUri(String rootURI)`, the full URI must be used in the javadoc:org.springframework.test.web.client.MockRestServiceServer[] expectations as shown in the following example: +When using a javadoc:org.springframework.web.client.RestClient$Builder[] in the beans under test, or when using a javadoc:org.springframework.boot.restclient.RestTemplateBuilder[] without calling `baseUri(String baseUri)`, the full URI must be used in the javadoc:org.springframework.test.web.client.MockRestServiceServer[] expectations as shown in the following example: include-code::MyRestClientServiceTests[] diff --git a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc index cd517fe18e3c..92bde635fa73 100644 --- a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc +++ b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc @@ -200,7 +200,7 @@ For example, a javadoc:{url-testcontainers-postgresql-javadoc}/org.testcontainer If you want to create only a subset of the applicable types, you can use the `type` attribute of javadoc:org.springframework.boot.testcontainers.service.connection.ServiceConnection[format=annotation]. To create a javadoc:org.springframework.boot.amqp.autoconfigure.RabbitStreamConnectionDetails[] bean from a javadoc:{url-testcontainers-rabbitmq-javadoc}/org.testcontainers.rabbitmq.RabbitMQContainer[], you must opt in using the `type` attribute of javadoc:org.springframework.boot.testcontainers.service.connection.ServiceConnection[format=annotation]. -The container must also expose port 5552, the RabbitMQ streams port. +The container must also expose port 5552, or port 5551 when SSL is configured, for RabbitMQ Streams. ==== By default `Container.getDockerImageName().getRepository()` is used to obtain the name used to find connection details. diff --git a/module/spring-boot-security-oauth2-client/src/main/java/org/springframework/boot/security/oauth2/client/autoconfigure/OAuth2ClientProperties.java b/module/spring-boot-security-oauth2-client/src/main/java/org/springframework/boot/security/oauth2/client/autoconfigure/OAuth2ClientProperties.java index c87a49c033d6..f57b8a81f74c 100644 --- a/module/spring-boot-security-oauth2-client/src/main/java/org/springframework/boot/security/oauth2/client/autoconfigure/OAuth2ClientProperties.java +++ b/module/spring-boot-security-oauth2-client/src/main/java/org/springframework/boot/security/oauth2/client/autoconfigure/OAuth2ClientProperties.java @@ -79,7 +79,7 @@ public static class Registration { /** * Reference to the OAuth 2.0 provider to use. May reference one of the common - * providers (google, github, facebook, okta) or the ID of a custom provider + * providers (google, github, facebook, x, okta) or the ID of a custom provider * configured using 'spring.security.oauth2.client.provider.<id>.*' * properties. When not set, the ID of this registration is used to identify the * provider. From 248f6eee0160958ce2d32e145d4aabe45093dca3 Mon Sep 17 00:00:00 2001 From: Doehyun Baek Date: Fri, 12 Jun 2026 05:18:37 +0000 Subject: [PATCH 07/10] Align docs with recent changes Signed-off-by: Doehyun Baek See gh-50759 --- .../src/docs/antora/modules/reference/pages/data/sql.adoc | 2 +- .../modules/reference/pages/features/external-config.adoc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/data/sql.adoc b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/data/sql.adoc index fa8a38f48cf2..4b87a7e1ea40 100644 --- a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/data/sql.adoc +++ b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/data/sql.adoc @@ -274,7 +274,7 @@ include-code::CityRepository[] Spring Data JPA repositories support three different modes of bootstrapping: default, deferred, and lazy. To enable deferred or lazy bootstrapping, set the configprop:spring.data.jpa.repositories.bootstrap-mode[] property to `deferred` or `lazy` respectively. -When using deferred or lazy bootstrapping, the auto-configured javadoc:org.springframework.boot.jpa.EntityManagerFactoryBuilder[] will use the context's javadoc:org.springframework.core.task.AsyncTaskExecutor[], if any, as the bootstrap executor. +When using deferred bootstrapping, the auto-configured javadoc:org.springframework.boot.jpa.EntityManagerFactoryBuilder[] requires a bootstrap executor and will use the context's javadoc:org.springframework.core.task.AsyncTaskExecutor[], if one can be determined. If more than one exists, the one named `applicationTaskExecutor` will be used. [NOTE] diff --git a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/external-config.adoc b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/external-config.adoc index 38d348e788c7..9ce3d49f2430 100644 --- a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/external-config.adoc +++ b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/external-config.adoc @@ -874,7 +874,7 @@ This will happen automatically if you use Spring Boot's Gradle plugin or if you NOTE: The use of javadoc:java.util.Optional[] with javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] is not recommended as it is primarily intended for use as a return type. As such, it is not well-suited to configuration property injection. -For consistency with properties of other types, if you do declare an javadoc:java.util.Optional[] property and it has no value, `null` rather than an empty javadoc:java.util.Optional[] will be bound. +If you do declare an javadoc:java.util.Optional[] constructor-bound property and it has no value, an empty javadoc:java.util.Optional[] will be bound. TIP: To use a reserved keyword in the name of a property, such as `my.service.import`, use the javadoc:org.springframework.boot.context.properties.bind.Name[format=annotation] annotation on the constructor parameter. From 8eb3b032a4010f7bc75351fb3cc0585c98b2b7b7 Mon Sep 17 00:00:00 2001 From: Vinod Kumar Date: Thu, 11 Jun 2026 19:41:38 +0530 Subject: [PATCH 08/10] Treat empty JWK Set URI as absent Signed-off-by: Vinod Kumar See gh-50755 --- .../autoconfigure/JwkSetUriCondition.java | 45 +++++++++++++++++++ ...2ResourceServerAutoConfigurationTests.java | 12 +++++ 2 files changed, 57 insertions(+) create mode 100644 module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/JwkSetUriCondition.java diff --git a/module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/JwkSetUriCondition.java b/module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/JwkSetUriCondition.java new file mode 100644 index 000000000000..5562b2798d60 --- /dev/null +++ b/module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/JwkSetUriCondition.java @@ -0,0 +1,45 @@ +/* + * Copyright 2012-present 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.security.oauth2.server.resource.autoconfigure; + +import org.springframework.boot.autoconfigure.condition.ConditionMessage; +import org.springframework.boot.autoconfigure.condition.ConditionOutcome; +import org.springframework.boot.autoconfigure.condition.SpringBootCondition; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.core.env.Environment; +import org.springframework.core.type.AnnotatedTypeMetadata; +import org.springframework.util.StringUtils; + +/** + * Condition for creating a JWT decoder using a JWK Set URI. + * + * @author Vinod Kumar M + */ +class JwkSetUriCondition extends SpringBootCondition { + + @Override + public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { + ConditionMessage.Builder message = ConditionMessage.forCondition("JWK Set URI Condition"); + Environment environment = context.getEnvironment(); + String jwkSetUri = environment.getProperty("spring.security.oauth2.resourceserver.jwt.jwk-set-uri"); + if (!StringUtils.hasText(jwkSetUri)) { + return ConditionOutcome.noMatch(message.didNotFind("jwk-set-uri property").atAll()); + } + return ConditionOutcome.match(message.foundExactly("jwk-set-uri property")); + } + +} \ No newline at end of file diff --git a/module/spring-boot-security-oauth2-resource-server/src/test/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/servlet/OAuth2ResourceServerAutoConfigurationTests.java b/module/spring-boot-security-oauth2-resource-server/src/test/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/servlet/OAuth2ResourceServerAutoConfigurationTests.java index 556cbf77060f..20624cab6e15 100644 --- a/module/spring-boot-security-oauth2-resource-server/src/test/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/servlet/OAuth2ResourceServerAutoConfigurationTests.java +++ b/module/spring-boot-security-oauth2-resource-server/src/test/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/servlet/OAuth2ResourceServerAutoConfigurationTests.java @@ -362,6 +362,18 @@ void autoConfigurationWhenSetUriKeyLocationAndIssuerUriPresentShouldUseSetUri() assertThat(context.containsBean("jwtDecoderByIssuerUri")).isFalse(); }); } + + @Test + void autoConfigurationWhenIssuerUriPresentAndJwkSetUriEmptyShouldUseIssuerUri() { + this.contextRunner + .withPropertyValues("spring.security.oauth2.resourceserver.jwt.issuer-uri=https://issuer-uri.com", + "spring.security.oauth2.resourceserver.jwt.jwk-set-uri=") + .run((context) -> { + assertThat(context).hasSingleBean(JwtDecoder.class); + assertThat(context.containsBean("jwtDecoderByJwkKeySetUri")).isFalse(); + assertThat(context.containsBean("jwtDecoderByIssuerUri")).isTrue(); + }); + } @Test void autoConfigurationWhenKeyLocationAndIssuerUriPresentShouldUseIssuerUri() throws Exception { From a49549203b47bc8a9aa5aa5cb8d9e544539100ff Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 24 Jun 2026 17:45:32 +0100 Subject: [PATCH 09/10] Polish "Treat empty JWK Set URI as absent" See gh-50755 Signed-off-by: Andy Wilkinson --- .../ConditionalOnJwkSetUriJwtDecoder.java | 42 +++++++++++++++++++ .../autoconfigure/JwkSetUriCondition.java | 4 +- ...eOAuth2ResourceServerJwtConfiguration.java | 3 +- .../OAuth2ResourceServerJwtConfiguration.java | 3 +- ...2ResourceServerAutoConfigurationTests.java | 12 ++++++ ...2ResourceServerAutoConfigurationTests.java | 2 +- 6 files changed, 61 insertions(+), 5 deletions(-) create mode 100644 module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/ConditionalOnJwkSetUriJwtDecoder.java diff --git a/module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/ConditionalOnJwkSetUriJwtDecoder.java b/module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/ConditionalOnJwkSetUriJwtDecoder.java new file mode 100644 index 000000000000..c6793b353de5 --- /dev/null +++ b/module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/ConditionalOnJwkSetUriJwtDecoder.java @@ -0,0 +1,42 @@ +/* + * Copyright 2012-present 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.security.oauth2.server.resource.autoconfigure; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.context.annotation.Conditional; +import org.springframework.security.oauth2.jwt.NimbusJwtDecoder; +import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder; + +/** + * Condition that matches when a JWK Set URI based {@link NimbusJwtDecoder} or + * {@link NimbusReactiveJwtDecoder} should be used. + * + * @author Andy Wilkinson + * @since 4.0.8 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Documented +@Conditional(JwkSetUriCondition.class) +public @interface ConditionalOnJwkSetUriJwtDecoder { + +} diff --git a/module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/JwkSetUriCondition.java b/module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/JwkSetUriCondition.java index 5562b2798d60..589d0b74b89f 100644 --- a/module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/JwkSetUriCondition.java +++ b/module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/JwkSetUriCondition.java @@ -5,7 +5,7 @@ * 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 + * 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, @@ -42,4 +42,4 @@ public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeM return ConditionOutcome.match(message.foundExactly("jwk-set-uri property")); } -} \ No newline at end of file +} diff --git a/module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/reactive/ReactiveOAuth2ResourceServerJwtConfiguration.java b/module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/reactive/ReactiveOAuth2ResourceServerJwtConfiguration.java index 9b648e80e90e..9b4adc17474d 100644 --- a/module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/reactive/ReactiveOAuth2ResourceServerJwtConfiguration.java +++ b/module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/reactive/ReactiveOAuth2ResourceServerJwtConfiguration.java @@ -35,6 +35,7 @@ import org.springframework.boot.context.properties.PropertyMapper; import org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException; import org.springframework.boot.security.oauth2.server.resource.autoconfigure.ConditionalOnIssuerLocationJwtDecoder; +import org.springframework.boot.security.oauth2.server.resource.autoconfigure.ConditionalOnJwkSetUriJwtDecoder; import org.springframework.boot.security.oauth2.server.resource.autoconfigure.ConditionalOnPublicKeyJwtDecoder; import org.springframework.boot.security.oauth2.server.resource.autoconfigure.OAuth2ResourceServerProperties; import org.springframework.context.annotation.Bean; @@ -92,7 +93,7 @@ static class JwtConfiguration { } @Bean - @ConditionalOnProperty(name = "spring.security.oauth2.resourceserver.jwt.jwk-set-uri") + @ConditionalOnJwkSetUriJwtDecoder ReactiveJwtDecoder jwtDecoder(ObjectProvider customizers) { String jwkSetUri = this.properties.getJwkSetUri(); Assert.state(jwkSetUri != null, "'jwkSetUri' must not be null"); diff --git a/module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/servlet/OAuth2ResourceServerJwtConfiguration.java b/module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/servlet/OAuth2ResourceServerJwtConfiguration.java index 3ea6dc80ee5d..2f9e477d8db6 100644 --- a/module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/servlet/OAuth2ResourceServerJwtConfiguration.java +++ b/module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/servlet/OAuth2ResourceServerJwtConfiguration.java @@ -36,6 +36,7 @@ import org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException; import org.springframework.boot.security.autoconfigure.web.servlet.ConditionalOnDefaultWebSecurity; import org.springframework.boot.security.oauth2.server.resource.autoconfigure.ConditionalOnIssuerLocationJwtDecoder; +import org.springframework.boot.security.oauth2.server.resource.autoconfigure.ConditionalOnJwkSetUriJwtDecoder; import org.springframework.boot.security.oauth2.server.resource.autoconfigure.ConditionalOnPublicKeyJwtDecoder; import org.springframework.boot.security.oauth2.server.resource.autoconfigure.OAuth2ResourceServerProperties; import org.springframework.context.annotation.Bean; @@ -92,7 +93,7 @@ static class JwtDecoderConfiguration { } @Bean - @ConditionalOnProperty(name = "spring.security.oauth2.resourceserver.jwt.jwk-set-uri") + @ConditionalOnJwkSetUriJwtDecoder JwtDecoder jwtDecoderByJwkKeySetUri(ObjectProvider customizers) { JwkSetUriJwtDecoderBuilder builder = NimbusJwtDecoder.withJwkSetUri(this.properties.getJwkSetUri()) .jwsAlgorithms(this::jwsAlgorithms); diff --git a/module/spring-boot-security-oauth2-resource-server/src/test/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java b/module/spring-boot-security-oauth2-resource-server/src/test/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java index db204052ccf3..ab737ca6bd7e 100644 --- a/module/spring-boot-security-oauth2-resource-server/src/test/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java +++ b/module/spring-boot-security-oauth2-resource-server/src/test/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java @@ -444,6 +444,18 @@ void autoConfigurationWhenJwkSetUriAndIntrospectionUriAvailable() { }); } + @Test + void autoConfigurationWhenIssuerUriPresentAndJwkSetUriEmptyShouldUseIssuerUri() { + this.contextRunner + .withPropertyValues("spring.security.oauth2.resourceserver.jwt.issuer-uri=https://issuer-uri.com", + "spring.security.oauth2.resourceserver.jwt.jwk-set-uri=") + .run((context) -> { + assertThat(context).hasSingleBean(ReactiveJwtDecoder.class); + assertThat(context.containsBean("jwtDecoder")).isFalse(); + assertThat(context.containsBean("jwtDecoderByIssuerUri")).isTrue(); + }); + } + @Test void opaqueTokenIntrospectorIsConditionalOnMissingBean() { this.contextRunner diff --git a/module/spring-boot-security-oauth2-resource-server/src/test/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/servlet/OAuth2ResourceServerAutoConfigurationTests.java b/module/spring-boot-security-oauth2-resource-server/src/test/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/servlet/OAuth2ResourceServerAutoConfigurationTests.java index 20624cab6e15..b6e472d29611 100644 --- a/module/spring-boot-security-oauth2-resource-server/src/test/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/servlet/OAuth2ResourceServerAutoConfigurationTests.java +++ b/module/spring-boot-security-oauth2-resource-server/src/test/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/servlet/OAuth2ResourceServerAutoConfigurationTests.java @@ -362,7 +362,7 @@ void autoConfigurationWhenSetUriKeyLocationAndIssuerUriPresentShouldUseSetUri() assertThat(context.containsBean("jwtDecoderByIssuerUri")).isFalse(); }); } - + @Test void autoConfigurationWhenIssuerUriPresentAndJwkSetUriEmptyShouldUseIssuerUri() { this.contextRunner From 463d68c19ae63ad9f64387d6d4361d6aa92efc3e Mon Sep 17 00:00:00 2001 From: vipi-n Date: Wed, 10 Jun 2026 14:49:50 +0530 Subject: [PATCH 10/10] Fix duplicate word typos in documentation Signed-off-by: vipi-n See gh-50738 --- .../boot/actuate/docs/info/InfoEndpointDocumentationTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/spring-boot-actuator-docs/src/test/java/org/springframework/boot/actuate/docs/info/InfoEndpointDocumentationTests.java b/documentation/spring-boot-actuator-docs/src/test/java/org/springframework/boot/actuate/docs/info/InfoEndpointDocumentationTests.java index 0d11d51829b7..e4ea34a4f993 100644 --- a/documentation/spring-boot-actuator-docs/src/test/java/org/springframework/boot/actuate/docs/info/InfoEndpointDocumentationTests.java +++ b/documentation/spring-boot-actuator-docs/src/test/java/org/springframework/boot/actuate/docs/info/InfoEndpointDocumentationTests.java @@ -119,7 +119,7 @@ private ResponseFieldsSnippet processInfo() { fieldWithPath("memory.nonHeap.max") .description("Maximum number of bytes that can be used by the JVM (or -1)."), fieldWithPath("memory.garbageCollectors").description("Details for garbage collectors."), - fieldWithPath("memory.garbageCollectors[].name").description("Name of of the garbage collector."), + fieldWithPath("memory.garbageCollectors[].name").description("Name of the garbage collector."), fieldWithPath("memory.garbageCollectors[].collectionCount") .description("Total number of collections that have occurred."), fieldWithPath("virtualThreads")