From a0f98727460aab99a641ed558aec84ebd2997c44 Mon Sep 17 00:00:00 2001 From: rstoyanchev Date: Wed, 18 Jun 2025 16:48:32 +0100 Subject: [PATCH] Refactor construction of VersionRequestCondition The single constructor now supports all combinations of having a version attribute set or not, and ApiVersionStrategy, configured or not. In effective, ensure the configured ApiVersionStrategy is passed even when the RequestMapping version attribute is not set. See gh-35082 --- .../condition/VersionRequestCondition.java | 49 ++++++++++--------- .../result/method/RequestMappingInfo.java | 29 ++++------- .../VersionRequestConditionTests.java | 23 +++++---- .../condition/VersionRequestCondition.java | 49 ++++++++++--------- .../mvc/method/RequestMappingInfo.java | 29 ++++------- .../VersionRequestConditionTests.java | 23 +++++---- 6 files changed, 94 insertions(+), 108 deletions(-) diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/condition/VersionRequestCondition.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/condition/VersionRequestCondition.java index 76eb0b82060..ceb1d51f255 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/condition/VersionRequestCondition.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/condition/VersionRequestCondition.java @@ -23,6 +23,7 @@ import java.util.Set; import org.jspecify.annotations.Nullable; import org.springframework.util.Assert; +import org.springframework.util.StringUtils; import org.springframework.web.accept.InvalidApiVersionException; import org.springframework.web.accept.NotAcceptableApiVersionException; import org.springframework.web.bind.annotation.RequestMapping; @@ -58,20 +59,24 @@ public final class VersionRequestCondition extends AbstractRequestCondition content; - public VersionRequestCondition() { - this.versionValue = null; - this.version = null; - this.baselineVersion = false; - this.versionStrategy = NO_OP_VERSION_STRATEGY; - this.content = Collections.emptySet(); - } - - public VersionRequestCondition(String configuredVersion, ApiVersionStrategy versionStrategy) { - this.baselineVersion = configuredVersion.endsWith("+"); - this.versionValue = updateVersion(configuredVersion, this.baselineVersion); - this.version = versionStrategy.parseVersion(this.versionValue); - this.versionStrategy = versionStrategy; - this.content = Set.of(configuredVersion); + /** + * Constructor with the version, if set on the {@code @RequestMapping}, and + * the {@code ApiVersionStrategy}, if API versioning is enabled. + */ + public VersionRequestCondition(@Nullable String version, @Nullable ApiVersionStrategy strategy) { + this.versionStrategy = (strategy != null ? strategy : NO_OP_VERSION_STRATEGY); + if (StringUtils.hasText(version)) { + this.baselineVersion = version.endsWith("+"); + this.versionValue = updateVersion(version, this.baselineVersion); + this.version = this.versionStrategy.parseVersion(this.versionValue); + this.content = Set.of(version); + } + else { + this.versionValue = null; + this.version = null; + this.baselineVersion = false; + this.content = Collections.emptySet(); + } } private static String updateVersion(String version, boolean baselineVersion) { @@ -104,23 +109,23 @@ public final class VersionRequestCondition extends AbstractRequestCondition version = exchange.getAttribute(VERSION_ATTRIBUTE_NAME); - if (version == null) { + Comparable requestVersion = exchange.getAttribute(VERSION_ATTRIBUTE_NAME); + if (requestVersion == null) { String value = this.versionStrategy.resolveVersion(exchange); - version = (value != null ? parseVersion(value) : this.versionStrategy.getDefaultVersion()); - this.versionStrategy.validateVersion(version, exchange); - version = (version != null ? version : NO_VERSION_ATTRIBUTE); - exchange.getAttributes().put(VERSION_ATTRIBUTE_NAME, (version)); + requestVersion = (value != null ? parseVersion(value) : this.versionStrategy.getDefaultVersion()); + this.versionStrategy.validateVersion(requestVersion, exchange); + requestVersion = (requestVersion != null ? requestVersion : NO_VERSION_ATTRIBUTE); + exchange.getAttributes().put(VERSION_ATTRIBUTE_NAME, (requestVersion)); } - if (version == NO_VERSION_ATTRIBUTE) { + if (requestVersion == NO_VERSION_ATTRIBUTE) { return this; } // At this stage, match all versions as baseline versions. // Strict matching for fixed versions is enforced at the end in handleMatch. - int result = compareVersions(this.version, version); + int result = compareVersions(this.version, requestVersion); return (result <= 0 ? this : null); } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/RequestMappingInfo.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/RequestMappingInfo.java index 7ee51821822..b70ab318f24 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/RequestMappingInfo.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/RequestMappingInfo.java @@ -71,8 +71,6 @@ public final class RequestMappingInfo implements RequestCondition content; - public VersionRequestCondition() { - this.versionValue = null; - this.version = null; - this.baselineVersion = false; - this.versionStrategy = NO_OP_VERSION_STRATEGY; - this.content = Collections.emptySet(); - } - - public VersionRequestCondition(String configuredVersion, ApiVersionStrategy versionStrategy) { - this.baselineVersion = configuredVersion.endsWith("+"); - this.versionValue = updateVersion(configuredVersion, this.baselineVersion); - this.version = versionStrategy.parseVersion(this.versionValue); - this.versionStrategy = versionStrategy; - this.content = Set.of(configuredVersion); + /** + * Constructor with the version, if set on the {@code @RequestMapping}, and + * the {@code ApiVersionStrategy}, if API versioning is enabled. + */ + public VersionRequestCondition(@Nullable String version, @Nullable ApiVersionStrategy strategy) { + this.versionStrategy = (strategy != null ? strategy : NO_OP_VERSION_STRATEGY); + if (StringUtils.hasText(version)) { + this.baselineVersion = version.endsWith("+"); + this.versionValue = updateVersion(version, this.baselineVersion); + this.version = this.versionStrategy.parseVersion(this.versionValue); + this.content = Set.of(version); + } + else { + this.versionValue = null; + this.version = null; + this.baselineVersion = false; + this.content = Collections.emptySet(); + } } private static String updateVersion(String version, boolean baselineVersion) { @@ -103,23 +108,23 @@ public final class VersionRequestCondition extends AbstractRequestCondition version = (Comparable) request.getAttribute(VERSION_ATTRIBUTE_NAME); - if (version == null) { + Comparable requestVersion = (Comparable) request.getAttribute(VERSION_ATTRIBUTE_NAME); + if (requestVersion == null) { String value = this.versionStrategy.resolveVersion(request); - version = (value != null ? parseVersion(value) : this.versionStrategy.getDefaultVersion()); - this.versionStrategy.validateVersion(version, request); - version = (version != null ? version : NO_VERSION_ATTRIBUTE); - request.setAttribute(VERSION_ATTRIBUTE_NAME, (version)); + requestVersion = (value != null ? parseVersion(value) : this.versionStrategy.getDefaultVersion()); + this.versionStrategy.validateVersion(requestVersion, request); + requestVersion = (requestVersion != null ? requestVersion : NO_VERSION_ATTRIBUTE); + request.setAttribute(VERSION_ATTRIBUTE_NAME, (requestVersion)); } - if (version == NO_VERSION_ATTRIBUTE) { + if (requestVersion == NO_VERSION_ATTRIBUTE) { return this; } // At this stage, match all versions as baseline versions. // Strict matching for fixed versions is enforced at the end in handleMatch. - int result = compareVersions(this.version, version); + int result = compareVersions(this.version, requestVersion); return (result <= 0 ? this : null); } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/RequestMappingInfo.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/RequestMappingInfo.java index 87db7f4f5b0..3a400624b4f 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/RequestMappingInfo.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/RequestMappingInfo.java @@ -80,8 +80,6 @@ public final class RequestMappingInfo implements RequestCondition