diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/result/StatusResultMatchers.java b/spring-test/src/main/java/org/springframework/test/web/servlet/result/StatusResultMatchers.java index 9c2b01e942f..ee1a58163ab 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/result/StatusResultMatchers.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/result/StatusResultMatchers.java @@ -145,8 +145,18 @@ public class StatusResultMatchers { /** * Assert the response status code is {@code HttpStatus.CHECKPOINT} (103). + * @see #isEarlyHints() + * @deprecated in favor of {@link #isEarlyHints()} */ + @Deprecated(since = "6.0") public ResultMatcher isCheckpoint() { + return isEarlyHints(); + } + + /** + * Assert the response status code is {@code HttpStatus.EARLY_HINTS} (103). + */ + public ResultMatcher isEarlyHints() { return matcher(HttpStatus.valueOf(103)); } diff --git a/spring-test/src/main/kotlin/org/springframework/test/web/servlet/result/StatusResultMatchersDsl.kt b/spring-test/src/main/kotlin/org/springframework/test/web/servlet/result/StatusResultMatchersDsl.kt index ef5b7748290..dc05aba4d11 100644 --- a/spring-test/src/main/kotlin/org/springframework/test/web/servlet/result/StatusResultMatchersDsl.kt +++ b/spring-test/src/main/kotlin/org/springframework/test/web/servlet/result/StatusResultMatchersDsl.kt @@ -115,12 +115,21 @@ class StatusResultMatchersDsl internal constructor (private val actions: ResultA } /** - * @see StatusResultMatchers.isCheckpoint + * @see isEarlyHints */ + @Deprecated("use isEarlyHints() instead", replaceWith= ReplaceWith("isEarlyHints()")) fun isCheckpoint() { + @Suppress("DEPRECATION") actions.andExpect(matchers.isCheckpoint()) } + /** + * @see StatusResultMatchers.isEarlyHints + */ + fun isEarlyHints() { + actions.andExpect(matchers.isEarlyHints()) + } + /** * @see StatusResultMatchers.isOk */ diff --git a/spring-web/src/main/java/org/springframework/http/HttpStatus.java b/spring-web/src/main/java/org/springframework/http/HttpStatus.java index 7d878f936d8..38d33b184ab 100644 --- a/spring-web/src/main/java/org/springframework/http/HttpStatus.java +++ b/spring-web/src/main/java/org/springframework/http/HttpStatus.java @@ -50,11 +50,18 @@ public enum HttpStatus implements HttpStatusCode { * @see WebDAV */ PROCESSING(102, Series.INFORMATIONAL, "Processing"), + /** + * {code 103 Early Hints}. + * @see An HTTP Status Code for Indicating Hints + */ + EARLY_HINTS(103, Series.INFORMATIONAL, "Early Hints"), /** * {@code 103 Checkpoint}. * @see A proposal for supporting * resumable POST/PUT HTTP requests in HTTP/1.0 + * @deprecated in favor of {@link #EARLY_HINTS} which will be returned from {@code HttpStatus.valueOf(103)} */ + @Deprecated(since = "6.0") CHECKPOINT(103, Series.INFORMATIONAL, "Checkpoint"), // 2xx Success diff --git a/spring-web/src/main/java/org/springframework/http/HttpStatusCode.java b/spring-web/src/main/java/org/springframework/http/HttpStatusCode.java index 380ba2aa57c..0b16b6ca2a9 100644 --- a/spring-web/src/main/java/org/springframework/http/HttpStatusCode.java +++ b/spring-web/src/main/java/org/springframework/http/HttpStatusCode.java @@ -76,6 +76,16 @@ public sealed interface HttpStatusCode extends Serializable permits DefaultHttpS */ boolean isError(); + /** + * Whether this {@code HttpStatusCode} shares the same integer {@link #value() value} as the other status code. + *

Useful for comparisons that take deprecated aliases into account or compare arbitrary implementations + * of {@code HttpStatusCode} (e.g. in place of {@link HttpStatus#equals(Object) HttpStatus enum equality}). + * @param other the other {@code HttpStatusCode} to compare + * @return true if the two {@code HttpStatusCode} share the same integer {@code value()}, false otherwise + */ + default boolean isSameCodeAs(HttpStatusCode other) { + return value() == other.value(); + } /** * Return an {@code HttpStatusCode} object for the given integer value. diff --git a/spring-web/src/test/java/org/springframework/http/HttpStatusTests.java b/spring-web/src/test/java/org/springframework/http/HttpStatusTests.java index cec1f9ad960..473c6ab0ce2 100644 --- a/spring-web/src/test/java/org/springframework/http/HttpStatusTests.java +++ b/spring-web/src/test/java/org/springframework/http/HttpStatusTests.java @@ -17,12 +17,19 @@ package org.springframework.http; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.params.provider.Arguments.arguments; /** * @author Arjen Poutsma @@ -37,7 +44,7 @@ class HttpStatusTests { statusCodes.put(100, "CONTINUE"); statusCodes.put(101, "SWITCHING_PROTOCOLS"); statusCodes.put(102, "PROCESSING"); - statusCodes.put(103, "CHECKPOINT"); + statusCodes.put(103, "EARLY_HINTS"); statusCodes.put(200, "OK"); statusCodes.put(201, "CREATED"); @@ -120,8 +127,7 @@ class HttpStatusTests { void fromEnumToMap() { for (HttpStatus status : HttpStatus.values()) { int code = status.value(); - // The following status codes have more than one corresponding HttpStatus enum constant. - if (code == 302 || code == 413 || code == 414) { + if (DEPRECATED_CODES.contains(status)) { continue; } assertThat(statusCodes).as("Map has no value for [" + code + "]").containsKey(code); @@ -138,4 +144,35 @@ class HttpStatusTests { } } + @ParameterizedTest(name = "[{index}] code {0}") + @MethodSource("codesWithAliases") + void codeWithDeprecatedAlias(int code, HttpStatus expected, HttpStatus outdated) { + HttpStatus resolved = HttpStatus.valueOf(code); + assertThat(resolved) + .as("HttpStatus.valueOf(" + code + ")") + .isSameAs(expected) + .isNotEqualTo(outdated); + assertThat(outdated.isSameCodeAs(resolved)) + .as("outdated isSameCodeAs(resolved)") + .isTrue(); + assertThat(outdated.value()) + .as("outdated value()") + .isEqualTo(resolved.value()); + } + + private static final Set DEPRECATED_CODES = codesWithAliases() + .stream() + .map(args -> (HttpStatus) args.get()[2]) + .collect(Collectors.toUnmodifiableSet()); + + @SuppressWarnings("deprecation") + static List codesWithAliases() { + return List.of( + arguments(103, HttpStatus.EARLY_HINTS, HttpStatus.CHECKPOINT), + arguments(302, HttpStatus.FOUND, HttpStatus.MOVED_TEMPORARILY), + arguments(413, HttpStatus.PAYLOAD_TOO_LARGE, HttpStatus.REQUEST_ENTITY_TOO_LARGE), + arguments(414, HttpStatus.URI_TOO_LONG, HttpStatus.REQUEST_URI_TOO_LONG) + ); + } + }