Skip to content

Commit 58c7a0f

Browse files
committed
Merge branch '4.0.x'
Closes gh-50127
2 parents 61ca2f5 + 1aaef07 commit 58c7a0f

6 files changed

Lines changed: 75 additions & 7 deletions

File tree

documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/web/reactive.adoc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ The same `@Controller` path can be mapped multiple times to support different ve
284284
For more details see {url-spring-framework-docs}/web/webflux/controller/ann-requestmapping.html#webflux-ann-requestmapping-version[Spring Framework's reference documentation].
285285

286286
Once mappings have been added, you additionally need to configure Spring WebFlux so that it is able to use any version information sent with a request.
287-
Typically, versions are sent as HTTP headers, query parameters or as part of the path.
287+
Typically, versions are sent as HTTP headers, query parameters, media type parameters, or as part of the path.
288288

289289
To configure Spring WebFlux, you can either use a javadoc:org.springframework.web.reactive.config.WebFluxConfigurer[] bean and override the `configureApiVersioning(...)` method, or you can use properties.
290290

@@ -300,7 +300,9 @@ spring:
300300
header: X-Version
301301
----
302302

303-
For more complete control, you can also define javadoc:org.springframework.web.reactive.accept.ApiVersionResolver[], javadoc:org.springframework.web.accept.ApiVersionParser[] and javadoc:org.springframework.web.reactive.accept.ApiVersionDeprecationHandler[] beans which will be injected into the auto-configured Spring MVC configuration.
303+
NOTE: If your setup requires multiple strategies, such as header and query parameter, consider declaring the order programmatically by overriding the `configureApiVersioning` method.
304+
305+
For more complete control, you can also define javadoc:org.springframework.web.reactive.accept.ApiVersionResolver[], javadoc:org.springframework.web.accept.ApiVersionParser[] and javadoc:org.springframework.web.reactive.accept.ApiVersionDeprecationHandler[] beans which will be injected into the auto-configured Spring WebFlux configuration.
304306

305307
TIP: API versioning is also supported on the client-side with both `WebClient` and `RestClient`.
306308
See xref:io/rest-client.adoc#io.rest-client.apiversioning[] for details.

documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/web/servlet.adoc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -474,8 +474,8 @@ The same `@Controller` path can be mapped multiple times to support different ve
474474

475475
For more details see {url-spring-framework-docs}/web/webmvc/mvc-controller/ann-requestmapping.html#mvc-ann-requestmapping-version[Spring Framework's reference documentation].
476476

477-
One mappings have been added, you additionally need to configure Spring MVC so that it is able to use any version information sent with a request.
478-
Typically, versions are sent as HTTP headers, query parameters or as part of the path.
477+
Once mappings have been added, you additionally need to configure Spring MVC so that it is able to use any version information sent with a request.
478+
Typically, versions are sent as HTTP headers, query parameters, media type parameters, or as part of the path.
479479

480480
To configure Spring MVC, you can either use a javadoc:org.springframework.web.servlet.config.annotation.WebMvcConfigurer[] bean and override the `configureApiVersioning(...)` method, or you can use properties.
481481

@@ -491,6 +491,8 @@ spring:
491491
header: X-Version
492492
----
493493

494+
NOTE: If your setup requires multiple strategies, such as header and query parameter, consider declaring the order programmatically by overriding the `configureApiVersioning` method.
495+
494496
For more complete control, you can also define javadoc:org.springframework.web.accept.ApiVersionResolver[], javadoc:org.springframework.web.accept.ApiVersionParser[] and javadoc:org.springframework.web.accept.ApiVersionDeprecationHandler[] beans which will be injected into the auto-configured Spring MVC configuration.
495497

496498
TIP: API versioning is also supported with both `WebClient` and `RestClient`.

module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/WebFluxAutoConfiguration.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -301,9 +301,8 @@ private void configureApiVersioningUse(ApiVersionConfigurer configurer, Use use)
301301
PropertyMapper map = PropertyMapper.get();
302302
map.from(use::getHeader).whenHasText().to(configurer::useRequestHeader);
303303
map.from(use::getQueryParameter).whenHasText().to(configurer::useQueryParam);
304+
use.getMediaTypeParameter().forEach(configurer::useMediaTypeParameter);
304305
map.from(use::getPathSegment).to(configurer::usePathSegment);
305-
use.getMediaTypeParameter()
306-
.forEach((mediaType, parameterName) -> configurer.useMediaTypeParameter(mediaType, parameterName));
307306
}
308307

309308
}

module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/autoconfigure/WebFluxAutoConfigurationTests.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -909,6 +909,35 @@ void apiVersionUseMediaTypeParameterPropertyIsApplied() {
909909
});
910910
}
911911

912+
@Test
913+
void apiVersionUsesPathSegmentLast() {
914+
this.contextRunner
915+
.withPropertyValues("spring.webflux.apiversion.use.path-segment=1",
916+
"spring.webflux.apiversion.use.header=hv", "spring.webflux.apiversion.use.query-parameter=rpv",
917+
"spring.webflux.apiversion.use.media-type-parameter[application/json]=mtpv")
918+
.run((context) -> {
919+
DefaultApiVersionStrategy versionStrategy = context.getBean("webFluxApiVersionStrategy",
920+
DefaultApiVersionStrategy.class);
921+
922+
MockServerWebExchange requestWithHeader = MockServerWebExchange
923+
.from(MockServerHttpRequest.get("https://example.com/test/456").header("hv", "123"));
924+
assertThat(versionStrategy.resolveVersion(requestWithHeader)).isEqualTo("123");
925+
926+
MockServerWebExchange requestWithQueryParameter = MockServerWebExchange
927+
.from(MockServerHttpRequest.get("https://example.com?rpv=123"));
928+
assertThat(versionStrategy.resolveVersion(requestWithQueryParameter)).isEqualTo("123");
929+
930+
MockServerWebExchange requestWithMediaType = MockServerWebExchange
931+
.from(MockServerHttpRequest.get("https://example.com/test/456")
932+
.header("content-type", "application/json;mtpv=123"));
933+
assertThat(versionStrategy.resolveVersion(requestWithMediaType)).isEqualTo("123");
934+
935+
MockServerWebExchange requestFallbacksToApiSegment = MockServerWebExchange
936+
.from(MockServerHttpRequest.get("https://example.com/test/456"));
937+
assertThat(versionStrategy.resolveVersion(requestFallbacksToApiSegment)).isEqualTo("456");
938+
});
939+
}
940+
912941
@Test
913942
void apiVersionBeansAreInjected() {
914943
this.contextRunner.withUserConfiguration(ApiVersionConfiguration.class).run((context) -> {

module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/WebMvcAutoConfiguration.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -421,8 +421,8 @@ private void configureApiVersioningUse(ApiVersionConfigurer configurer, Use use)
421421
PropertyMapper map = PropertyMapper.get();
422422
map.from(use::getHeader).whenHasText().to(configurer::useRequestHeader);
423423
map.from(use::getQueryParameter).whenHasText().to(configurer::useQueryParam);
424-
map.from(use::getPathSegment).to(configurer::usePathSegment);
425424
use.getMediaTypeParameter().forEach(configurer::useMediaTypeParameter);
425+
map.from(use::getPathSegment).to(configurer::usePathSegment);
426426
}
427427

428428
@Bean

module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/WebMvcAutoConfigurationTests.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,6 +1122,42 @@ void apiVersionUseMediaTypeParameterPropertyIsApplied() {
11221122
});
11231123
}
11241124

1125+
@Test
1126+
void apiVersionUsesPathSegmentLast() {
1127+
this.contextRunner
1128+
.withPropertyValues("spring.mvc.apiversion.use.path-segment=1", "spring.mvc.apiversion.use.header=hv",
1129+
"spring.mvc.apiversion.use.query-parameter=rpv",
1130+
"spring.mvc.apiversion.use.media-type-parameter[application/json]=mtpv")
1131+
.run((context) -> {
1132+
ApiVersionStrategy versionStrategy = context.getBean("mvcApiVersionStrategy", ApiVersionStrategy.class);
1133+
1134+
MockHttpServletRequest requestWithHeader = new MockHttpServletRequest("GET",
1135+
"https://example.com/test/456");
1136+
requestWithHeader.addHeader("hv", "123");
1137+
ServletRequestPathUtils.setParsedRequestPath(RequestPath.parse("/test/456", "/"), requestWithHeader);
1138+
assertThat(versionStrategy.resolveVersion(requestWithHeader)).isEqualTo("123");
1139+
1140+
MockHttpServletRequest requestWithQueryParameter = new MockHttpServletRequest("GET",
1141+
"https://example.com/test/456");
1142+
requestWithQueryParameter.setQueryString("rpv=123");
1143+
ServletRequestPathUtils.setParsedRequestPath(RequestPath.parse("/test/456", "/"),
1144+
requestWithQueryParameter);
1145+
assertThat(versionStrategy.resolveVersion(requestWithQueryParameter)).isEqualTo("123");
1146+
1147+
MockHttpServletRequest requestWithMediaType = new MockHttpServletRequest("GET",
1148+
"https://example.com/test/456");
1149+
ServletRequestPathUtils.setParsedRequestPath(RequestPath.parse("/test/456", "/"), requestWithMediaType);
1150+
requestWithMediaType.addHeader(HttpHeaders.CONTENT_TYPE, "application/json;mtpv=123");
1151+
assertThat(versionStrategy.resolveVersion(requestWithMediaType)).isEqualTo("123");
1152+
1153+
MockHttpServletRequest requestFallbacksToApiSegment = new MockHttpServletRequest("GET",
1154+
"https://example.com/test/456");
1155+
ServletRequestPathUtils.setParsedRequestPath(RequestPath.parse("/test/456", "/"),
1156+
requestFallbacksToApiSegment);
1157+
assertThat(versionStrategy.resolveVersion(requestFallbacksToApiSegment)).isEqualTo("456");
1158+
});
1159+
}
1160+
11251161
@Test
11261162
void apiVersionBeansAreInjected() {
11271163
this.contextRunner.withUserConfiguration(ApiVersionConfiguration.class).run((context) -> {

0 commit comments

Comments
 (0)