Add detectSupportedVersions in spring-webmvc

Closes gh-35105
This commit is contained in:
rstoyanchev
2025-06-25 12:03:35 +01:00
parent 3cb8a833e4
commit 482cfb0b18
8 changed files with 138 additions and 59 deletions
@@ -44,10 +44,14 @@ public class DefaultApiVersionStrategy implements ApiVersionStrategy {
private final @Nullable Comparable<?> defaultVersion;
private final @Nullable ApiVersionDeprecationHandler deprecationHandler;
private final Set<Comparable<?>> supportedVersions = new TreeSet<>();
private final boolean detectSupportedVersions;
private final Set<Comparable<?>> detectedVersions = new TreeSet<>();
private final @Nullable ApiVersionDeprecationHandler deprecationHandler;
/**
* Create an instance.
@@ -59,12 +63,15 @@ public class DefaultApiVersionStrategy implements ApiVersionStrategy {
* validation fails with {@link MissingApiVersionException}
* @param defaultVersion a default version to assign to requests that
* don't specify one
* @param detectSupportedVersions whether to use API versions that appear in
* mappings for supported version validation (true), or use only explicitly
* configured versions (false).
* @param deprecationHandler handler to send hints and information about
* deprecated API versions to clients
*/
public DefaultApiVersionStrategy(
List<ApiVersionResolver> versionResolvers, ApiVersionParser<?> versionParser,
boolean versionRequired, @Nullable String defaultVersion,
boolean versionRequired, @Nullable String defaultVersion, boolean detectSupportedVersions,
@Nullable ApiVersionDeprecationHandler deprecationHandler) {
Assert.notEmpty(versionResolvers, "At least one ApiVersionResolver is required");
@@ -74,6 +81,7 @@ public class DefaultApiVersionStrategy implements ApiVersionStrategy {
this.versionParser = versionParser;
this.versionRequired = (versionRequired && defaultVersion == null);
this.defaultVersion = (defaultVersion != null ? versionParser.parseVersion(defaultVersion) : null);
this.detectSupportedVersions = detectSupportedVersions;
this.deprecationHandler = deprecationHandler;
}
@@ -84,11 +92,15 @@ public class DefaultApiVersionStrategy implements ApiVersionStrategy {
}
/**
* Add to the list of known, supported versions to check against in
* {@link ApiVersionStrategy#validateVersion}. Request versions that are not
* in the supported result in {@link InvalidApiVersionException}
* in {@link ApiVersionStrategy#validateVersion}.
* @param versions the versions to add
* Add to the list of supported versions to check against in
* {@link ApiVersionStrategy#validateVersion} before raising
* {@link InvalidApiVersionException} for unknown versions.
* <p>By default, actual version values that appear in request mappings are
* considered supported, and use of this method is optional. However, if you
* prefer to use only explicitly configured, supported versions, then set
* {@code detectSupportedVersions} flag to {@code false}.
* @param versions the supported versions to add
* @see #addMappedVersion(String...)
*/
public void addSupportedVersion(String... versions) {
for (String version : versions) {
@@ -96,6 +108,22 @@ public class DefaultApiVersionStrategy implements ApiVersionStrategy {
}
}
/**
* Internal method to add to the list of actual version values that appear in
* request mappings, which allows supported versions to be discovered rather
* than {@link #addSupportedVersion(String...) configured}.
* <p>If you prefer to use explicitly configured, supported versions only,
* set the {@code detectSupportedVersions} flag to {@code false}.
* @param versions the versions to add
* @see #addSupportedVersion(String...)
*/
public void addMappedVersion(String... versions) {
for (String version : versions) {
this.detectedVersions.add(parseVersion(version));
}
}
@Override
public @Nullable String resolveVersion(HttpServletRequest request) {
for (ApiVersionResolver resolver : this.versionResolvers) {
@@ -122,11 +150,16 @@ public class DefaultApiVersionStrategy implements ApiVersionStrategy {
return;
}
if (!this.supportedVersions.contains(requestVersion)) {
if (!isSupportedVersion(requestVersion)) {
throw new InvalidApiVersionException(requestVersion.toString());
}
}
private boolean isSupportedVersion(Comparable<?> requestVersion) {
return (this.supportedVersions.contains(requestVersion) ||
this.detectSupportedVersions && this.detectedVersions.contains(requestVersion));
}
@Override
public void handleDeprecations(Comparable<?> version, HttpServletRequest request, HttpServletResponse response) {
if (this.deprecationHandler != null) {
@@ -136,8 +169,12 @@ public class DefaultApiVersionStrategy implements ApiVersionStrategy {
@Override
public String toString() {
return "DefaultApiVersionStrategy[supportedVersions=" + this.supportedVersions +
", versionRequired=" + this.versionRequired + ", defaultVersion=" + this.defaultVersion + "]";
return "DefaultApiVersionStrategy[" +
"supportedVersions=" + this.supportedVersions + ", " +
"mappedVersions=" + this.detectedVersions + ", " +
"detectSupportedVersions=" + this.detectSupportedVersions + ", " +
"versionRequired=" + this.versionRequired + ", " +
"defaultVersion=" + this.defaultVersion + "]";
}
}