mirror of
https://github.com/spring-projects/spring-framework.git
synced 2026-09-17 16:39:29 +00:00
Update contribution
- deprecate sync method on ApiVersionResolver - add SyncApiVersionResolver - refactor resolverParseAndValidateApiVersion method See gh-36084
This commit is contained in:
+7
-6
@@ -29,8 +29,7 @@ import org.springframework.web.server.ServerWebExchange;
|
||||
* @since 7.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public
|
||||
interface ApiVersionResolver {
|
||||
public interface ApiVersionResolver {
|
||||
|
||||
/**
|
||||
* Resolve the version for the given exchange.
|
||||
@@ -40,15 +39,17 @@ interface ApiVersionResolver {
|
||||
* @return {@code Mono} emitting the version value, or an empty {@code Mono}
|
||||
* @since 7.0.3
|
||||
*/
|
||||
default Mono<String> resolveApiVersion(ServerWebExchange exchange){
|
||||
return Mono.justOrEmpty(this.resolveVersion(exchange));
|
||||
}
|
||||
Mono<String> resolveApiVersion(ServerWebExchange exchange);
|
||||
|
||||
/**
|
||||
* Resolve the version for the given exchange.
|
||||
* @param exchange the current exchange
|
||||
* @return the version value, or {@code null} if not found
|
||||
* @deprecated in favor of {@link #resolveApiVersion(ServerWebExchange)}
|
||||
*/
|
||||
@Nullable String resolveVersion(ServerWebExchange exchange);
|
||||
@Deprecated(since = "7.0.3", forRemoval = true)
|
||||
default @Nullable String resolveVersion(ServerWebExchange exchange) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+19
-28
@@ -88,40 +88,31 @@ public interface ApiVersionStrategy {
|
||||
* or an empty {@code Mono} if there is no version
|
||||
* @since 7.0.3
|
||||
*/
|
||||
@SuppressWarnings("Convert2MethodRef")
|
||||
default Mono<Comparable<?>> resolveParseAndValidateApiVersion(ServerWebExchange exchange) {
|
||||
return this.resolveApiVersion(exchange)
|
||||
.switchIfEmpty(Mono.justOrEmpty(this.getDefaultVersion())
|
||||
.mapNotNull(comparable -> comparable.toString()))
|
||||
.<Comparable<?>>handle((version, sink) -> {
|
||||
|
||||
Mono<Comparable<?>> result = resolveApiVersion(exchange)
|
||||
.map(value -> {
|
||||
Comparable<?> version;
|
||||
try {
|
||||
sink.next(this.parseVersion(version));
|
||||
version = parseVersion(value);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
sink.error(new InvalidApiVersionException(version, null, ex));
|
||||
throw new InvalidApiVersionException(value, null, ex);
|
||||
}
|
||||
})
|
||||
.flatMap(version -> this.validateVersionAsync(version, exchange))
|
||||
.switchIfEmpty(this.validateVersionAsync(null, exchange));
|
||||
}
|
||||
validateVersion(version, exchange);
|
||||
return version;
|
||||
});
|
||||
|
||||
/**
|
||||
* Validates the provided request version against the requirements and constraints
|
||||
* of the API. If the validation succeeds, the version is returned, otherwise an
|
||||
* error is emitted.
|
||||
* @param requestVersion the version to validate, which may be null
|
||||
* @param exchange the current server exchange representing the HTTP request and response
|
||||
* @return a {@code Mono} emitting the validated request version as a {@code Comparable<?>},
|
||||
* or an error if validation fails
|
||||
*/
|
||||
default Mono<Comparable<?>> validateVersionAsync(@Nullable Comparable<?> requestVersion, ServerWebExchange exchange) {
|
||||
try {
|
||||
this.validateVersion(requestVersion, exchange);
|
||||
return Mono.justOrEmpty(requestVersion);
|
||||
}
|
||||
catch (MissingApiVersionException | InvalidApiVersionException ex) {
|
||||
return Mono.error(ex);
|
||||
}
|
||||
return result.switchIfEmpty(Mono.fromSupplier(() -> {
|
||||
Comparable<?> defaultVersion = getDefaultVersion();
|
||||
if (defaultVersion != null) {
|
||||
return defaultVersion;
|
||||
}
|
||||
else {
|
||||
validateVersion(null, exchange);
|
||||
return null;
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+2
-2
@@ -26,7 +26,7 @@ import org.springframework.web.server.ServerWebExchange;
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 7.0
|
||||
*/
|
||||
public class HeaderApiVersionResolver implements ApiVersionResolver {
|
||||
public class HeaderApiVersionResolver implements SyncApiVersionResolver {
|
||||
|
||||
private final String headerName;
|
||||
|
||||
@@ -37,7 +37,7 @@ public class HeaderApiVersionResolver implements ApiVersionResolver {
|
||||
|
||||
|
||||
@Override
|
||||
public @Nullable String resolveVersion(ServerWebExchange exchange) {
|
||||
public @Nullable String resolveVersionValue(ServerWebExchange exchange) {
|
||||
return exchange.getRequest().getHeaders().getFirst(this.headerName);
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -29,7 +29,7 @@ import org.springframework.web.server.ServerWebExchange;
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 7.0
|
||||
*/
|
||||
public class MediaTypeParamApiVersionResolver implements ApiVersionResolver {
|
||||
public class MediaTypeParamApiVersionResolver implements SyncApiVersionResolver {
|
||||
|
||||
private final MediaType compatibleMediaType;
|
||||
|
||||
@@ -49,7 +49,7 @@ public class MediaTypeParamApiVersionResolver implements ApiVersionResolver {
|
||||
|
||||
|
||||
@Override
|
||||
public @Nullable String resolveVersion(ServerWebExchange exchange) {
|
||||
public @Nullable String resolveVersionValue(ServerWebExchange exchange) {
|
||||
HttpHeaders headers = exchange.getRequest().getHeaders();
|
||||
for (MediaType mediaType : headers.getAccept()) {
|
||||
if (this.compatibleMediaType.isCompatibleWith(mediaType)) {
|
||||
|
||||
+2
-2
@@ -32,7 +32,7 @@ import org.springframework.web.server.ServerWebExchange;
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 7.0
|
||||
*/
|
||||
public class PathApiVersionResolver implements ApiVersionResolver {
|
||||
public class PathApiVersionResolver implements SyncApiVersionResolver {
|
||||
|
||||
private final int pathSegmentIndex;
|
||||
|
||||
@@ -49,7 +49,7 @@ public class PathApiVersionResolver implements ApiVersionResolver {
|
||||
|
||||
|
||||
@Override
|
||||
public String resolveVersion(ServerWebExchange exchange) {
|
||||
public String resolveVersionValue(ServerWebExchange exchange) {
|
||||
int i = 0;
|
||||
for (PathContainer.Element e : exchange.getRequest().getPath().pathWithinApplication().elements()) {
|
||||
if (e instanceof PathContainer.PathSegment && i++ == this.pathSegmentIndex) {
|
||||
|
||||
+2
-2
@@ -26,7 +26,7 @@ import org.springframework.web.server.ServerWebExchange;
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 7.0
|
||||
*/
|
||||
public class QueryApiVersionResolver implements ApiVersionResolver {
|
||||
public class QueryApiVersionResolver implements SyncApiVersionResolver {
|
||||
|
||||
private final String queryParamName;
|
||||
|
||||
@@ -37,7 +37,7 @@ public class QueryApiVersionResolver implements ApiVersionResolver {
|
||||
|
||||
|
||||
@Override
|
||||
public @Nullable String resolveVersion(ServerWebExchange exchange) {
|
||||
public @Nullable String resolveVersionValue(ServerWebExchange exchange) {
|
||||
return exchange.getRequest().getQueryParams().getFirst(this.queryParamName);
|
||||
}
|
||||
|
||||
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2002-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.web.reactive.accept;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
/**
|
||||
* An extension of {@link ApiVersionResolver}s for implementations that can
|
||||
* resolve the version in an imperative way without blocking.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 7.0.3
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface SyncApiVersionResolver extends ApiVersionResolver {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>This method delegates to the synchronous
|
||||
* {@link #resolveVersionValue} and wraps the result as {@code Mono}.
|
||||
*/
|
||||
@Override
|
||||
default Mono<String> resolveApiVersion(ServerWebExchange exchange) {
|
||||
return Mono.justOrEmpty(resolveVersionValue(exchange));
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the version for the given exchange imperatively without blocking.
|
||||
* @param exchange the current exchange
|
||||
* @return the version value, or {@code null} if not found
|
||||
*/
|
||||
@Nullable String resolveVersionValue(ServerWebExchange exchange);
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
@Override
|
||||
default @Nullable String resolveVersion(ServerWebExchange exchange) {
|
||||
return resolveVersionValue(exchange);
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -137,7 +137,7 @@ public class DefaultApiVersionStrategiesTests {
|
||||
@Nullable Predicate<Comparable<?>> supportedVersionPredicate) {
|
||||
|
||||
return new DefaultApiVersionStrategy(
|
||||
List.of(exchange -> exchange.getRequest().getQueryParams().getFirst("api-version")),
|
||||
List.of(new QueryApiVersionResolver("api-version")),
|
||||
parser, null, defaultVersion, detectSupportedVersions, supportedVersionPredicate, null);
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -22,6 +22,7 @@ import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
@@ -380,7 +381,7 @@ class RequestPredicatesTests {
|
||||
|
||||
private static DefaultApiVersionStrategy apiVersionStrategy() {
|
||||
return new DefaultApiVersionStrategy(
|
||||
List.of(exchange -> null), new SemanticApiVersionParser(), true, null, false, null, null);
|
||||
List.of(exchange -> Mono.empty()), new SemanticApiVersionParser(), true, null, false, null, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-1
@@ -28,6 +28,7 @@ import org.springframework.web.accept.NotAcceptableApiVersionException;
|
||||
import org.springframework.web.accept.SemanticApiVersionParser;
|
||||
import org.springframework.web.reactive.HandlerMapping;
|
||||
import org.springframework.web.reactive.accept.DefaultApiVersionStrategy;
|
||||
import org.springframework.web.reactive.accept.QueryApiVersionResolver;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.testfixture.http.server.reactive.MockServerHttpRequest;
|
||||
import org.springframework.web.testfixture.server.MockServerWebExchange;
|
||||
@@ -51,7 +52,7 @@ public class VersionRequestConditionTests {
|
||||
|
||||
private static DefaultApiVersionStrategy initVersionStrategy(@Nullable String defaultVersion) {
|
||||
return new DefaultApiVersionStrategy(
|
||||
List.of(exchange -> exchange.getRequest().getQueryParams().getFirst("api-version")),
|
||||
List.of(new QueryApiVersionResolver("api-version")),
|
||||
new SemanticApiVersionParser(), null, defaultVersion, false, null, null);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user