Declare redirectedUrl argument as @⁠Nullable

MockMvcResultMatchers.forwardedUrl() already accepts a @⁠Nullable
expected value to assert that no forwarding occurred, but its
counterpart redirectedUrl() previously did not, even though the
underlying assertEquals() comparison is null-safe and behaves the same
way for redirects.

To address that, this commit adds the same @⁠Nullable declaration to
redirectedUrl() and documents the null semantics in the Javadoc for
both methods.

Closes gh-37230
This commit is contained in:
Sam Brannen
2026-09-03 13:19:04 +02:00
parent f2fe79e56d
commit 7cdb326623
2 changed files with 37 additions and 5 deletions
@@ -85,7 +85,8 @@ public abstract class MockMvcResultMatchers {
/**
* Asserts the request was forwarded to the given URL.
* <p>This method accepts only exact matches.
* @param expectedUrl the exact URL expected
* @param expectedUrl the exact URL expected; or {@code null} to assert
* that no forwarding occurred
*/
public static ResultMatcher forwardedUrl(@Nullable String expectedUrl) {
return result -> assertEquals("Forwarded URL", expectedUrl, result.getResponse().getForwardedUrl());
@@ -124,9 +125,10 @@ public abstract class MockMvcResultMatchers {
/**
* Asserts the request was redirected to the given URL.
* <p>This method accepts only exact matches.
* @param expectedUrl the exact URL expected
* @param expectedUrl the exact URL expected; or {@code null} to assert
* that no redirect occurred
*/
public static ResultMatcher redirectedUrl(String expectedUrl) {
public static ResultMatcher redirectedUrl(@Nullable String expectedUrl) {
return result -> assertEquals("Redirected URL", expectedUrl, result.getResponse().getRedirectedUrl());
}
@@ -39,11 +39,17 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
class MockMvcResultMatchersTests {
@Test
void redirect() throws Exception {
void redirect() {
assertThatCode(() -> redirectedUrl("/resource/1").match(redirectedUrlStub("/resource/1")))
.doesNotThrowAnyException();
}
@Test // gh-37230
void redirectWithNullAssertsNoRedirectOccurred() {
assertThatCode(() -> redirectedUrl(null).match(noRedirectOrForwardStub()))
.doesNotThrowAnyException();
}
@Test
void redirectNonMatching() {
assertThatExceptionOfType(AssertionError.class)
@@ -58,6 +64,13 @@ class MockMvcResultMatchersTests {
.withMessageEndingWith("expected:</resource/1> but was:<null>");
}
@Test // gh-37230
void redirectWithNullNonMatchingBecauseRedirectOccurred() {
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> redirectedUrl(null).match(redirectedUrlStub("/resource/1")))
.withMessageEndingWith("expected:<null> but was:</resource/1>");
}
@Test
void redirectWithUrlTemplate() {
assertThatCode(() -> redirectedUrlTemplate("/orders/{orderId}/items/{itemId}", 1, 2).match(redirectedUrlStub("/orders/1/items/2")))
@@ -85,11 +98,17 @@ class MockMvcResultMatchersTests {
}
@Test
void forward() throws Exception {
void forward() {
assertThatCode(() -> forwardedUrl("/api/resource/1").match(forwardedUrlStub("/api/resource/1")))
.doesNotThrowAnyException();
}
@Test // gh-22155
void forwardWithNullAssertsNoForwardingOccurred() {
assertThatCode(() -> forwardedUrl(null).match(noRedirectOrForwardStub()))
.doesNotThrowAnyException();
}
@Test
void forwardNonMatching() {
assertThatExceptionOfType(AssertionError.class)
@@ -104,6 +123,13 @@ class MockMvcResultMatchersTests {
.withMessage("Forwarded URL 'null' does not match the expected URL pattern '/resource/*'");
}
@Test // gh-22155
void forwardWithNullNonMatchingBecauseForwardingOccurred() {
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> forwardedUrl(null).match(forwardedUrlStub("/resource/1")))
.withMessageEndingWith("expected:<null> but was:</resource/1>");
}
@Test
void forwardWithQueryString() {
assertThatCode(() -> forwardedUrl("/api/resource/1?arg=value").match(forwardedUrlStub("/api/resource/1?arg=value")))
@@ -136,6 +162,10 @@ class MockMvcResultMatchersTests {
.withMessage("Forwarded URL 'null' does not match the expected URL pattern '/resource/*'");
}
private StubMvcResult noRedirectOrForwardStub() {
return new StubMvcResult(null, null, null, null, null, null, new MockHttpServletResponse());
}
private StubMvcResult redirectedUrlStub(String redirectUrl) throws Exception {
MockHttpServletResponse response = new MockHttpServletResponse();
response.sendRedirect(redirectUrl);