Browse Source

Update contribution

- deprecate sync method on ApiVersionResolver
- add SyncApiVersionResolver
- refactor resolverParseAndValidateApiVersion method

See gh-36084
pull/36116/head
rstoyanchev 4 weeks ago
parent
commit
8ff89ffda2
  1. 13
      spring-webflux/src/main/java/org/springframework/web/reactive/accept/ApiVersionResolver.java
  2. 47
      spring-webflux/src/main/java/org/springframework/web/reactive/accept/ApiVersionStrategy.java
  3. 4
      spring-webflux/src/main/java/org/springframework/web/reactive/accept/HeaderApiVersionResolver.java
  4. 4
      spring-webflux/src/main/java/org/springframework/web/reactive/accept/MediaTypeParamApiVersionResolver.java
  5. 4
      spring-webflux/src/main/java/org/springframework/web/reactive/accept/PathApiVersionResolver.java
  6. 4
      spring-webflux/src/main/java/org/springframework/web/reactive/accept/QueryApiVersionResolver.java
  7. 57
      spring-webflux/src/main/java/org/springframework/web/reactive/accept/SyncApiVersionResolver.java
  8. 2
      spring-webflux/src/test/java/org/springframework/web/reactive/accept/DefaultApiVersionStrategiesTests.java
  9. 3
      spring-webflux/src/test/java/org/springframework/web/reactive/function/server/RequestPredicatesTests.java
  10. 3
      spring-webflux/src/test/java/org/springframework/web/reactive/result/condition/VersionRequestConditionTests.java

13
spring-webflux/src/main/java/org/springframework/web/reactive/accept/ApiVersionResolver.java

@ -29,8 +29,7 @@ import org.springframework.web.server.ServerWebExchange; @@ -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 { @@ -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;
}
}

47
spring-webflux/src/main/java/org/springframework/web/reactive/accept/ApiVersionStrategy.java

@ -88,40 +88,31 @@ public interface ApiVersionStrategy { @@ -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;
}
}));
}
/**

4
spring-webflux/src/main/java/org/springframework/web/reactive/accept/HeaderApiVersionResolver.java

@ -26,7 +26,7 @@ import org.springframework.web.server.ServerWebExchange; @@ -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 { @@ -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);
}

4
spring-webflux/src/main/java/org/springframework/web/reactive/accept/MediaTypeParamApiVersionResolver.java

@ -29,7 +29,7 @@ import org.springframework.web.server.ServerWebExchange; @@ -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 { @@ -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)) {

4
spring-webflux/src/main/java/org/springframework/web/reactive/accept/PathApiVersionResolver.java

@ -32,7 +32,7 @@ import org.springframework.web.server.ServerWebExchange; @@ -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 { @@ -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) {

4
spring-webflux/src/main/java/org/springframework/web/reactive/accept/QueryApiVersionResolver.java

@ -26,7 +26,7 @@ import org.springframework.web.server.ServerWebExchange; @@ -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 { @@ -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
spring-webflux/src/main/java/org/springframework/web/reactive/accept/SyncApiVersionResolver.java

@ -0,0 +1,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);
}
}

2
spring-webflux/src/test/java/org/springframework/web/reactive/accept/DefaultApiVersionStrategiesTests.java

@ -137,7 +137,7 @@ public class DefaultApiVersionStrategiesTests { @@ -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);
}

3
spring-webflux/src/test/java/org/springframework/web/reactive/function/server/RequestPredicatesTests.java

@ -22,6 +22,7 @@ import java.util.List; @@ -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 { @@ -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);
}
}

3
spring-webflux/src/test/java/org/springframework/web/reactive/result/condition/VersionRequestConditionTests.java

@ -28,6 +28,7 @@ import org.springframework.web.accept.NotAcceptableApiVersionException; @@ -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 { @@ -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);
}

Loading…
Cancel
Save