From dba148ea373c75ca4ca8e89f6995dac75488c6ed Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Thu, 31 Jul 2025 17:51:44 +0100 Subject: [PATCH] Adapt to upstream API version updates Closes gh-46519 --- .../autoconfigure/ApiversionProperties.java | 13 ++++++++ .../PropertiesApiVersionInserter.java | 1 + .../PropertiesApiVersionInserterTests.java | 4 +++ .../WebFluxAutoConfiguration.java | 6 ++-- .../autoconfigure/WebFluxProperties.java | 30 +++++++++---------- .../WebFluxAutoConfigurationTests.java | 4 +-- .../WebMvcAutoConfiguration.java | 6 ++-- .../autoconfigure/WebMvcProperties.java | 30 +++++++++---------- .../WebMvcAutoConfigurationTests.java | 6 ++-- 9 files changed, 59 insertions(+), 41 deletions(-) diff --git a/module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/autoconfigure/ApiversionProperties.java b/module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/autoconfigure/ApiversionProperties.java index 53002e03aa3..eace4cd4bdb 100644 --- a/module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/autoconfigure/ApiversionProperties.java +++ b/module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/autoconfigure/ApiversionProperties.java @@ -69,6 +69,11 @@ public class ApiversionProperties { */ private Integer pathSegment; + /** + * Insert the version into a media type parameter with the given name. + */ + private String mediaTypeParameter; + public String getHeader() { return this.header; } @@ -93,6 +98,14 @@ public class ApiversionProperties { this.pathSegment = pathSegment; } + public String getMediaTypeParameter() { + return this.mediaTypeParameter; + } + + public void setMediaTypeParameter(String mediaTypeParameter) { + this.mediaTypeParameter = mediaTypeParameter; + } + } } diff --git a/module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/autoconfigure/PropertiesApiVersionInserter.java b/module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/autoconfigure/PropertiesApiVersionInserter.java index a80daa961d7..0abb8ce78bf 100644 --- a/module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/autoconfigure/PropertiesApiVersionInserter.java +++ b/module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/autoconfigure/PropertiesApiVersionInserter.java @@ -98,6 +98,7 @@ public final class PropertiesApiVersionInserter implements ApiVersionInserter { map.from(insert::getHeader).whenHasText().as(counter::counted).to(builder::useHeader); map.from(insert::getQueryParameter).whenHasText().as(counter::counted).to(builder::useQueryParam); map.from(insert::getPathSegment).as(counter::counted).to(builder::usePathSegment); + map.from(insert::getMediaTypeParameter).to(builder::useMediaTypeParam); if (!counter.isEmpty()) { inserters.add(builder.build()); } diff --git a/module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/autoconfigure/PropertiesApiVersionInserterTests.java b/module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/autoconfigure/PropertiesApiVersionInserterTests.java index ea95221361d..a57aeace1fe 100644 --- a/module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/autoconfigure/PropertiesApiVersionInserterTests.java +++ b/module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/autoconfigure/PropertiesApiVersionInserterTests.java @@ -22,6 +22,7 @@ import java.util.Locale; import org.junit.jupiter.api.Test; import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; import org.springframework.web.client.ApiVersionFormatter; import org.springframework.web.client.ApiVersionInserter; @@ -60,12 +61,15 @@ class PropertiesApiVersionInserterTests { ApiversionProperties properties2 = new ApiversionProperties(); properties2.getInsert().setQueryParameter("v2"); properties2.getInsert().setPathSegment(1); + properties2.getInsert().setMediaTypeParameter("mtp"); ApiVersionInserter inserter = PropertiesApiVersionInserter.get(null, null, properties1, properties2); URI uri = new URI("https://example.com/foo/bar"); assertThat(inserter.insertVersion("123", uri)).hasToString("https://example.com/foo/123/bar?v1=123&v2=123"); HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); inserter.insertVersion("123", headers); assertThat(headers.get("x-test")).containsExactly("123"); + assertThat(headers.getContentType().getParameters()).containsEntry("mtp", "123"); } @Test diff --git a/module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/WebFluxAutoConfiguration.java b/module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/WebFluxAutoConfiguration.java index 499ab05327c..ff252ab8b91 100644 --- a/module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/WebFluxAutoConfiguration.java +++ b/module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/WebFluxAutoConfiguration.java @@ -276,10 +276,10 @@ public final class WebFluxAutoConfiguration { public void configureApiVersioning(ApiVersionConfigurer configurer) { PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); Apiversion properties = this.webFluxProperties.getApiversion(); - map.from(properties::isRequired).to(configurer::setVersionRequired); + map.from(properties::getRequired).to(configurer::setVersionRequired); map.from(properties::getDefaultVersion).to(configurer::setDefaultVersion); map.from(properties::getSupported).to((supported) -> supported.forEach(configurer::addSupportedVersions)); - map.from(properties::isDetectSupported).to(configurer::detectSupportedVersions); + map.from(properties::getDetectSupported).to(configurer::detectSupportedVersions); configureApiVersioningUse(configurer, properties.getUse()); this.apiVersionResolvers.orderedStream().forEach(configurer::useVersionResolver); this.apiVersionParser.ifAvailable(configurer::setVersionParser); @@ -289,7 +289,7 @@ public final class WebFluxAutoConfiguration { private void configureApiVersioningUse(ApiVersionConfigurer configurer, Use use) { PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); map.from(use::getHeader).whenHasText().to(configurer::useRequestHeader); - map.from(use::getRequestParameter).whenHasText().to(configurer::useRequestParam); + map.from(use::getQueryParameter).whenHasText().to(configurer::useQueryParam); map.from(use::getPathSegment).to(configurer::usePathSegment); use.getMediaTypeParameter() .forEach((mediaType, parameterName) -> configurer.useMediaTypeParameter(mediaType, parameterName)); diff --git a/module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/WebFluxProperties.java b/module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/WebFluxProperties.java index 5ce15f3adfa..b3ebc915cf6 100644 --- a/module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/WebFluxProperties.java +++ b/module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/WebFluxProperties.java @@ -176,7 +176,7 @@ public class WebFluxProperties { /** * Whether the API version is required with each request. */ - private boolean required = false; + private Boolean required; /** * Default version that should be used for each request. @@ -192,18 +192,18 @@ public class WebFluxProperties { /** * Whether supported versions should be detected from controllers. */ - private boolean detectSupported = true; + private Boolean detectSupported; /** * How version details should be inserted into requests. */ private final Use use = new Use(); - public boolean isRequired() { + public Boolean getRequired() { return this.required; } - public void setRequired(boolean required) { + public void setRequired(Boolean required) { this.required = required; } @@ -223,18 +223,18 @@ public class WebFluxProperties { this.supported = supported; } - public Use getUse() { - return this.use; - } - - public boolean isDetectSupported() { + public Boolean getDetectSupported() { return this.detectSupported; } - public void setDetectSupported(boolean detectSupported) { + public void setDetectSupported(Boolean detectSupported) { this.detectSupported = detectSupported; } + public Use getUse() { + return this.use; + } + public static class Use { /** @@ -245,7 +245,7 @@ public class WebFluxProperties { /** * Use the query parameter with the given name to obtain the version. */ - private String requestParameter; + private String queryParameter; /** * Use the path segment at the given index to obtain the version. @@ -265,12 +265,12 @@ public class WebFluxProperties { this.header = header; } - public String getRequestParameter() { - return this.requestParameter; + public String getQueryParameter() { + return this.queryParameter; } - public void setRequestParameter(String queryParameter) { - this.requestParameter = queryParameter; + public void setQueryParameter(String queryParameter) { + this.queryParameter = queryParameter; } public Integer getPathSegment() { diff --git a/module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/autoconfigure/WebFluxAutoConfigurationTests.java b/module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/autoconfigure/WebFluxAutoConfigurationTests.java index 1e6fceec7ed..a8c21f69086 100644 --- a/module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/autoconfigure/WebFluxAutoConfigurationTests.java +++ b/module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/autoconfigure/WebFluxAutoConfigurationTests.java @@ -850,8 +850,8 @@ class WebFluxAutoConfigurationTests { } @Test - void apiVersionUseRequestParameterPropertyIsApplied() { - this.contextRunner.withPropertyValues("spring.webflux.apiversion.use.request-parameter=rpv").run((context) -> { + void apiVersionUseQueryParameterPropertyIsApplied() { + this.contextRunner.withPropertyValues("spring.webflux.apiversion.use.query-parameter=rpv").run((context) -> { DefaultApiVersionStrategy versionStrategy = context.getBean("webFluxApiVersionStrategy", DefaultApiVersionStrategy.class); MockServerWebExchange request = MockServerWebExchange diff --git a/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/WebMvcAutoConfiguration.java b/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/WebMvcAutoConfiguration.java index 57b3d9588e9..484557675b8 100644 --- a/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/WebMvcAutoConfiguration.java +++ b/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/WebMvcAutoConfiguration.java @@ -390,10 +390,10 @@ public final class WebMvcAutoConfiguration { public void configureApiVersioning(ApiVersionConfigurer configurer) { PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); Apiversion properties = this.mvcProperties.getApiversion(); - map.from(properties::isRequired).to(configurer::setVersionRequired); + map.from(properties::getRequired).to(configurer::setVersionRequired); map.from(properties::getDefaultVersion).to(configurer::setDefaultVersion); map.from(properties::getSupported).to((supported) -> supported.forEach(configurer::addSupportedVersions)); - map.from(properties::isDetectSupported).to(configurer::detectSupportedVersions); + map.from(properties::getDetectSupported).to(configurer::detectSupportedVersions); configureApiVersioningUse(configurer, properties.getUse()); this.apiVersionResolvers.orderedStream().forEach(configurer::useVersionResolver); this.apiVersionParser.ifAvailable(configurer::setVersionParser); @@ -403,7 +403,7 @@ public final class WebMvcAutoConfiguration { private void configureApiVersioningUse(ApiVersionConfigurer configurer, Use use) { PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); map.from(use::getHeader).whenHasText().to(configurer::useRequestHeader); - map.from(use::getRequestParameter).whenHasText().to(configurer::useRequestParam); + map.from(use::getQueryParameter).whenHasText().to(configurer::useQueryParam); map.from(use::getPathSegment).to(configurer::usePathSegment); use.getMediaTypeParameter() .forEach((mediaType, parameterName) -> configurer.useMediaTypeParameter(mediaType, parameterName)); diff --git a/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/WebMvcProperties.java b/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/WebMvcProperties.java index e0bc81e65d0..49d8e2dcfe4 100644 --- a/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/WebMvcProperties.java +++ b/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/WebMvcProperties.java @@ -477,7 +477,7 @@ public class WebMvcProperties { /** * Whether the API version is required with each request. */ - private boolean required = false; + private Boolean required; /** * Default version that should be used for each request. @@ -493,18 +493,18 @@ public class WebMvcProperties { /** * Whether supported versions should be detected from controllers. */ - private boolean detectSupported = true; + private Boolean detectSupported; /** * How version details should be inserted into requests. */ private final Use use = new Use(); - public boolean isRequired() { + public Boolean getRequired() { return this.required; } - public void setRequired(boolean required) { + public void setRequired(Boolean required) { this.required = required; } @@ -524,18 +524,18 @@ public class WebMvcProperties { this.supported = supported; } - public Use getUse() { - return this.use; - } - - public boolean isDetectSupported() { + public Boolean getDetectSupported() { return this.detectSupported; } - public void setDetectSupported(boolean detectSupported) { + public void setDetectSupported(Boolean detectSupported) { this.detectSupported = detectSupported; } + public Use getUse() { + return this.use; + } + public static class Use { /** @@ -546,7 +546,7 @@ public class WebMvcProperties { /** * Use the query parameter with the given name to obtain the version. */ - private String requestParameter; + private String queryParameter; /** * Use the path segment at the given index to obtain the version. @@ -566,12 +566,12 @@ public class WebMvcProperties { this.header = header; } - public String getRequestParameter() { - return this.requestParameter; + public String getQueryParameter() { + return this.queryParameter; } - public void setRequestParameter(String queryParameter) { - this.requestParameter = queryParameter; + public void setQueryParameter(String queryParameter) { + this.queryParameter = queryParameter; } public Integer getPathSegment() { diff --git a/module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/WebMvcAutoConfigurationTests.java b/module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/WebMvcAutoConfigurationTests.java index a157bf2d1b4..a19c8b154a0 100644 --- a/module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/WebMvcAutoConfigurationTests.java +++ b/module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/WebMvcAutoConfigurationTests.java @@ -1060,11 +1060,11 @@ class WebMvcAutoConfigurationTests { } @Test - void apiVersionUseRequestParameterPropertyIsApplied() { - this.contextRunner.withPropertyValues("spring.mvc.apiversion.use.request-parameter=rpv").run((context) -> { + void apiVersionUseQueryParameterPropertyIsApplied() { + this.contextRunner.withPropertyValues("spring.mvc.apiversion.use.query-parameter=rpv").run((context) -> { ApiVersionStrategy versionStrategy = context.getBean("mvcApiVersionStrategy", ApiVersionStrategy.class); MockHttpServletRequest request = new MockHttpServletRequest(); - request.addParameter("rpv", "123"); + request.setQueryString("rpv=123"); assertThat(versionStrategy.resolveVersion(request)).isEqualTo("123"); }); }