diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ResponseEntityExceptionHandler.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ResponseEntityExceptionHandler.java
index eb47bb6e04..489ee14344 100644
--- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ResponseEntityExceptionHandler.java
+++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ResponseEntityExceptionHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2022 the original author or authors.
+ * Copyright 2002-2023 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.
@@ -50,6 +50,7 @@ import org.springframework.web.context.request.WebRequest;
import org.springframework.web.context.request.async.AsyncRequestTimeoutException;
import org.springframework.web.multipart.support.MissingServletRequestPartException;
import org.springframework.web.servlet.NoHandlerFoundException;
+import org.springframework.web.servlet.resource.NoResourceFoundException;
import org.springframework.web.util.WebUtils;
/**
@@ -121,6 +122,7 @@ public abstract class ResponseEntityExceptionHandler implements MessageSourceAwa
ServletRequestBindingException.class,
MethodArgumentNotValidException.class,
NoHandlerFoundException.class,
+ NoResourceFoundException.class,
AsyncRequestTimeoutException.class,
ErrorResponseException.class,
ConversionNotSupportedException.class,
@@ -158,6 +160,9 @@ public abstract class ResponseEntityExceptionHandler implements MessageSourceAwa
else if (ex instanceof NoHandlerFoundException subEx) {
return handleNoHandlerFoundException(subEx, subEx.getHeaders(), subEx.getStatusCode(), request);
}
+ else if (ex instanceof NoResourceFoundException subEx) {
+ return handleNoResourceFoundException(subEx, subEx.getHeaders(), subEx.getStatusCode(), request);
+ }
else if (ex instanceof AsyncRequestTimeoutException subEx) {
return handleAsyncRequestTimeoutException(subEx, subEx.getHeaders(), subEx.getStatusCode(), request);
}
@@ -348,6 +353,24 @@ public abstract class ResponseEntityExceptionHandler implements MessageSourceAwa
return handleExceptionInternal(ex, null, headers, status, request);
}
+ /**
+ * Customize the handling of {@link NoResourceFoundException}.
+ *
This method delegates to {@link #handleExceptionInternal}.
+ * @param ex the exception to handle
+ * @param headers the headers to use for the response
+ * @param status the status code to use for the response
+ * @param request the current request
+ * @return a {@code ResponseEntity} for the response to use, possibly
+ * {@code null} when the response is already committed
+ * @since 6.1
+ */
+ @Nullable
+ protected ResponseEntity handleNoResourceFoundException(
+ NoResourceFoundException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) {
+
+ return handleExceptionInternal(ex, null, headers, status, request);
+ }
+
/**
* Customize the handling of {@link AsyncRequestTimeoutException}.
* This method delegates to {@link #handleExceptionInternal}.
diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/support/DefaultHandlerExceptionResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/support/DefaultHandlerExceptionResolver.java
index dee6314ede..e919b23e07 100644
--- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/support/DefaultHandlerExceptionResolver.java
+++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/support/DefaultHandlerExceptionResolver.java
@@ -50,6 +50,7 @@ import org.springframework.web.multipart.support.MissingServletRequestPartExcept
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver;
+import org.springframework.web.servlet.resource.NoResourceFoundException;
import org.springframework.web.util.WebUtils;
/**
@@ -125,6 +126,10 @@ import org.springframework.web.util.WebUtils;
*
NoHandlerFoundException
* 404 (SC_NOT_FOUND)
*
+ *
+ * NoResourceFoundException
+ * 404 (SC_NOT_FOUND)
+ *
*
* AsyncRequestTimeoutException
* 503 (SC_SERVICE_UNAVAILABLE)
@@ -198,6 +203,9 @@ public class DefaultHandlerExceptionResolver extends AbstractHandlerExceptionRes
else if (ex instanceof NoHandlerFoundException theEx) {
mav = handleNoHandlerFoundException(theEx, request, response, handler);
}
+ else if (ex instanceof NoResourceFoundException theEx) {
+ mav = handleNoResourceFoundException(theEx, request, response, handler);
+ }
else if (ex instanceof AsyncRequestTimeoutException theEx) {
mav = handleAsyncRequestTimeoutException(theEx, request, response, handler);
}
@@ -413,6 +421,26 @@ public class DefaultHandlerExceptionResolver extends AbstractHandlerExceptionRes
return null;
}
+ /**
+ * Handle the case where no static resource was found.
+ * The default implementation returns {@code null} in which case the
+ * exception is handled in {@link #handleErrorResponse}.
+ * @param ex the {@link NoResourceFoundException} to be handled
+ * @param request current HTTP request
+ * @param response current HTTP response
+ * @param handler the resource handler
+ * @return an empty {@code ModelAndView} indicating the exception was handled, or
+ * {@code null} indicating the exception should be handled in {@link #handleErrorResponse}
+ * @throws IOException potentially thrown from {@link HttpServletResponse#sendError}
+ * @since 6.1
+ */
+ @Nullable
+ protected ModelAndView handleNoResourceFoundException(NoResourceFoundException ex,
+ HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException {
+
+ return null;
+ }
+
/**
* Handle the case where an async request timed out.
*
The default implementation returns {@code null} in which case the
diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/NoResourceFoundException.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/NoResourceFoundException.java
new file mode 100644
index 0000000000..bbdce08f24
--- /dev/null
+++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/NoResourceFoundException.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2002-2023 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.servlet.resource;
+
+import jakarta.servlet.ServletException;
+
+import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.HttpStatusCode;
+import org.springframework.http.ProblemDetail;
+import org.springframework.web.ErrorResponse;
+
+/**
+ * Raised when {@link ResourceHttpRequestHandler} can not find a resource.
+ *
+ * @author Rossen Stoyanchev
+ * @since 6.1
+ * @see org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler
+ * @see org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
+ */
+@SuppressWarnings("serial")
+public class NoResourceFoundException extends ServletException implements ErrorResponse {
+
+ private final HttpMethod httpMethod;
+
+ private final String resourcePath;
+
+ private final ProblemDetail body;
+
+
+ /**
+ * Create an instance.
+ */
+ public NoResourceFoundException(HttpMethod httpMethod, String resourcePath) {
+ super("No static resource " + resourcePath + ".");
+ this.httpMethod = httpMethod;
+ this.resourcePath = resourcePath;
+ this.body = ProblemDetail.forStatusAndDetail(getStatusCode(), getMessage());
+ }
+
+
+ /**
+ * Return the HTTP method for the request.
+ */
+ public HttpMethod getHttpMethod() {
+ return this.httpMethod;
+ }
+
+ /**
+ * Return the path used to locate the resource.
+ * @see org.springframework.web.servlet.HandlerMapping#PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE
+ */
+ public String getResourcePath() {
+ return this.resourcePath;
+ }
+
+ @Override
+ public HttpStatusCode getStatusCode() {
+ return HttpStatus.NOT_FOUND;
+ }
+
+ @Override
+ public ProblemDetail getBody() {
+ return this.body;
+ }
+
+}
diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java
index ab632ddfb6..1435c8b8be 100644
--- a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java
+++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2022 the original author or authors.
+ * Copyright 2002-2023 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.
@@ -537,8 +537,8 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
/**
* Processes a resource request.
- *
Checks for the existence of the requested resource in the configured list of locations.
- * If the resource does not exist, a {@code 404} response will be returned to the client.
+ *
Finds the requested resource under one of the configured locations.
+ * If the resource does not exist, {@link NoResourceFoundException} is raised.
* If the resource exists, the request will be checked for the presence of the
* {@code Last-Modified} header, and its value will be compared against the last-modified
* timestamp of the given resource, returning a {@code 304} status code if the
@@ -555,8 +555,7 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
Resource resource = getResource(request);
if (resource == null) {
logger.debug("Resource not found");
- response.sendError(HttpServletResponse.SC_NOT_FOUND);
- return;
+ throw new NoResourceFoundException(HttpMethod.valueOf(request.getMethod()), getPath(request));
}
if (HttpMethod.OPTIONS.matches(request.getMethod())) {
@@ -611,12 +610,7 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
@Nullable
protected Resource getResource(HttpServletRequest request) throws IOException {
- String path = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
- if (path == null) {
- throw new IllegalStateException("Required request attribute '" +
- HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE + "' is not set");
- }
-
+ String path = getPath(request);
path = processPath(path);
if (!StringUtils.hasText(path) || isInvalidPath(path)) {
return null;
@@ -635,6 +629,15 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
return resource;
}
+ private static String getPath(HttpServletRequest request) {
+ String path = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
+ if (path == null) {
+ throw new IllegalStateException("Required request attribute '" +
+ HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE + "' is not set");
+ }
+ return path;
+ }
+
/**
* Process the given resource path.
*
The default implementation replaces:
diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java
index 9e8db46a02..65191bbbb6 100644
--- a/spring-webmvc/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java
+++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java
@@ -114,6 +114,7 @@ import org.springframework.web.servlet.resource.CssLinkResourceTransformer;
import org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler;
import org.springframework.web.servlet.resource.EncodedResourceResolver;
import org.springframework.web.servlet.resource.FixedVersionStrategy;
+import org.springframework.web.servlet.resource.NoResourceFoundException;
import org.springframework.web.servlet.resource.PathResourceResolver;
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
import org.springframework.web.servlet.resource.ResourceResolver;
@@ -147,6 +148,7 @@ import org.springframework.web.util.UrlPathHelper;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.InstanceOfAssertFactories.BOOLEAN;
/**
@@ -417,8 +419,8 @@ public class MvcNamespaceTests {
for (HandlerInterceptor interceptor : chain.getInterceptorList()) {
interceptor.preHandle(request, response, chain.getHandler());
}
- ModelAndView mv = adapter.handle(request, response, chain.getHandler());
- assertThat((Object) mv).isNull();
+ assertThatThrownBy(() -> adapter.handle(request, response, chain.getHandler()))
+ .isInstanceOf(NoResourceFoundException.class);
}
@Test
diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ResponseEntityExceptionHandlerTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ResponseEntityExceptionHandlerTests.java
index ea8beabd82..b765e931be 100644
--- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ResponseEntityExceptionHandlerTests.java
+++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ResponseEntityExceptionHandlerTests.java
@@ -63,6 +63,7 @@ import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver;
+import org.springframework.web.servlet.resource.NoResourceFoundException;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import org.springframework.web.testfixture.servlet.MockHttpServletResponse;
import org.springframework.web.testfixture.servlet.MockServletConfig;
@@ -265,6 +266,11 @@ public class ResponseEntityExceptionHandlerTests {
assertThat(responseEntity.getHeaders()).isEmpty();
}
+ @Test
+ public void noResourceFoundException() {
+ testException(new NoResourceFoundException(HttpMethod.GET, "/resource"));
+ }
+
@Test
public void asyncRequestTimeoutException() {
testException(new AsyncRequestTimeoutException());
diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/support/DefaultHandlerExceptionResolverTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/support/DefaultHandlerExceptionResolverTests.java
index 9220b7ff5f..163fd5c064 100644
--- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/support/DefaultHandlerExceptionResolverTests.java
+++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/support/DefaultHandlerExceptionResolverTests.java
@@ -48,6 +48,7 @@ import org.springframework.web.multipart.support.MissingServletRequestPartExcept
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.NoHandlerFoundException;
+import org.springframework.web.servlet.resource.NoResourceFoundException;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import org.springframework.web.testfixture.servlet.MockHttpServletResponse;
@@ -182,7 +183,7 @@ public class DefaultHandlerExceptionResolverTests {
}
@Test
- public void handleMissingServletRequestPartException() throws Exception {
+ public void handleMissingServletRequestPartException() {
MissingServletRequestPartException ex = new MissingServletRequestPartException("name");
ModelAndView mav = exceptionResolver.resolveException(request, response, null, ex);
assertThat(mav).as("No ModelAndView returned").isNotNull();
@@ -194,7 +195,7 @@ public class DefaultHandlerExceptionResolverTests {
}
@Test
- public void handleBindException() throws Exception {
+ public void handleBindException() {
BindException ex = new BindException(new Object(), "name");
ModelAndView mav = exceptionResolver.resolveException(request, response, null, ex);
assertThat(mav).as("No ModelAndView returned").isNotNull();
@@ -203,7 +204,7 @@ public class DefaultHandlerExceptionResolverTests {
}
@Test
- public void handleNoHandlerFoundException() throws Exception {
+ public void handleNoHandlerFoundException() {
ServletServerHttpRequest req = new ServletServerHttpRequest(
new MockHttpServletRequest("GET","/resource"));
NoHandlerFoundException ex = new NoHandlerFoundException(req.getMethod().name(),
@@ -215,7 +216,16 @@ public class DefaultHandlerExceptionResolverTests {
}
@Test
- public void handleConversionNotSupportedException() throws Exception {
+ public void handleNoResourceFoundException() {
+ NoResourceFoundException ex = new NoResourceFoundException(HttpMethod.GET, "/resource");
+ ModelAndView mav = exceptionResolver.resolveException(request, response, null, ex);
+ assertThat(mav).as("No ModelAndView returned").isNotNull();
+ assertThat(mav.isEmpty()).as("No Empty ModelAndView returned").isTrue();
+ assertThat(response.getStatus()).as("Invalid status code").isEqualTo(404);
+ }
+
+ @Test
+ public void handleConversionNotSupportedException() {
ConversionNotSupportedException ex =
new ConversionNotSupportedException(new Object(), String.class, new Exception());
ModelAndView mav = exceptionResolver.resolveException(request, response, null, ex);
@@ -228,7 +238,7 @@ public class DefaultHandlerExceptionResolverTests {
}
@Test // SPR-14669
- public void handleAsyncRequestTimeoutException() throws Exception {
+ public void handleAsyncRequestTimeoutException() {
Exception ex = new AsyncRequestTimeoutException();
ModelAndView mav = exceptionResolver.resolveException(request, response, null, ex);
assertThat(mav).as("No ModelAndView returned").isNotNull();
diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandlerTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandlerTests.java
index a677cc685f..8b75309059 100644
--- a/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandlerTests.java
+++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandlerTests.java
@@ -29,7 +29,6 @@ import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.HttpMethod;
-import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.util.StringUtils;
import org.springframework.web.HttpRequestMethodNotSupportedException;
@@ -44,6 +43,7 @@ import org.springframework.web.testfixture.servlet.MockServletContext;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
@@ -367,11 +367,11 @@ class ResourceHttpRequestHandlerTests {
testInvalidPath("%2F%2F%2E%2E%2F%2F%2E%2E" + secretPath, handler);
}
- private void testInvalidPath(String requestPath, ResourceHttpRequestHandler handler) throws Exception {
+ private void testInvalidPath(String requestPath, ResourceHttpRequestHandler handler) {
this.request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, requestPath);
this.response = new MockHttpServletResponse();
- handler.handleRequest(this.request, this.response);
- assertThat(this.response.getStatus()).isEqualTo(HttpStatus.NOT_FOUND.value());
+ assertThatThrownBy(() -> handler.handleRequest(this.request, this.response))
+ .isInstanceOf(NoResourceFoundException.class);
}
@Test
@@ -409,19 +409,17 @@ class ResourceHttpRequestHandlerTests {
testResolvePathWithTraversal(location, "/ " + secretPath);
}
- private void testResolvePathWithTraversal(Resource location, String requestPath) throws Exception {
+ private void testResolvePathWithTraversal(Resource location, String requestPath) {
this.request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, requestPath);
this.response = new MockHttpServletResponse();
- this.handler.handleRequest(this.request, this.response);
- assertThat(this.response.getStatus()).isEqualTo(HttpStatus.NOT_FOUND.value());
+ assertNotFound();
}
@Test
- void ignoreInvalidEscapeSequence() throws Exception {
+ void ignoreInvalidEscapeSequence() {
this.request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "/%foo%/bar.txt");
this.response = new MockHttpServletResponse();
- this.handler.handleRequest(this.request, this.response);
- assertThat(this.response.getStatus()).isEqualTo(404);
+ assertNotFound();
}
@Test
@@ -506,32 +504,29 @@ class ResourceHttpRequestHandlerTests {
@Test
void directory() throws Exception {
this.request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "js/");
- this.handler.handleRequest(this.request, this.response);
- assertThat(this.response.getStatus()).isEqualTo(404);
+ assertNotFound();
}
@Test
void directoryInJarFile() throws Exception {
this.request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "underscorejs/");
- this.handler.handleRequest(this.request, this.response);
- assertThat(this.response.getStatus()).isEqualTo(404);
+ assertNotFound();
}
@Test
- void missingResourcePath() throws Exception {
+ void missingResourcePath() {
this.request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "");
- this.handler.handleRequest(this.request, this.response);
- assertThat(this.response.getStatus()).isEqualTo(404);
+ assertNotFound();
}
@Test
- void noPathWithinHandlerMappingAttribute() throws Exception {
+ void noPathWithinHandlerMappingAttribute() {
assertThatIllegalStateException().isThrownBy(() ->
this.handler.handleRequest(this.request, this.response));
}
@Test
- void unsupportedHttpMethod() throws Exception {
+ void unsupportedHttpMethod() {
this.request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "foo.css");
this.request.setMethod("POST");
assertThatExceptionOfType(HttpRequestMethodNotSupportedException.class).isThrownBy(() ->
@@ -539,19 +534,18 @@ class ResourceHttpRequestHandlerTests {
}
@Test
- void resourceNotFound() throws Exception {
+ void testResourceNotFound() {
for (HttpMethod method : HttpMethod.values()) {
this.request = new MockHttpServletRequest("GET", "");
this.response = new MockHttpServletResponse();
- resourceNotFound(method);
+ testResourceNotFound(method);
}
}
- private void resourceNotFound(HttpMethod httpMethod) throws Exception {
+ private void testResourceNotFound(HttpMethod httpMethod) {
this.request.setMethod(httpMethod.name());
this.request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "not-there.css");
- this.handler.handleRequest(this.request, this.response);
- assertThat(this.response.getStatus()).isEqualTo(HttpStatus.NOT_FOUND.value());
+ assertNotFound();
}
@Test
@@ -756,6 +750,11 @@ class ResourceHttpRequestHandlerTests {
}
+ private void assertNotFound() {
+ assertThatThrownBy(() -> this.handler.handleRequest(this.request, this.response))
+ .isInstanceOf(NoResourceFoundException.class);
+ }
+
private long resourceLastModified(String resourceName) throws IOException {
return new ClassPathResource(resourceName, getClass()).getFile().lastModified();
}