Change MethodNotAllowedException to use HttpMethod

Changed the MethodNotAllowedException to use HttpMethod, instead of
Strings.
This commit is contained in:
Arjen Poutsma
2017-03-22 16:38:26 +01:00
parent 4db2daae5c
commit 290e9bea14
5 changed files with 53 additions and 58 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2017 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.
@@ -21,6 +21,7 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.util.Assert;
@@ -33,14 +34,21 @@ import org.springframework.util.Assert;
@SuppressWarnings("serial")
public class MethodNotAllowedException extends ResponseStatusException {
private String method;
private final String method;
private Set<String> supportedMethods;
private final Set<HttpMethod> supportedMethods;
public MethodNotAllowedException(String method, Collection<String> supportedMethods) {
public MethodNotAllowedException(HttpMethod method, Collection<HttpMethod> supportedMethods) {
this(method.name(), supportedMethods);
}
public MethodNotAllowedException(String method, Collection<HttpMethod> supportedMethods) {
super(HttpStatus.METHOD_NOT_ALLOWED, "Request method '" + method + "' not supported");
Assert.notNull(method, "'method' is required");
if (supportedMethods == null) {
supportedMethods = Collections.emptySet();
}
this.method = method;
this.supportedMethods = Collections.unmodifiableSet(new HashSet<>(supportedMethods));
}
@@ -56,7 +64,7 @@ public class MethodNotAllowedException extends ResponseStatusException {
/**
* Return the list of supported HTTP methods.
*/
public Set<String> getSupportedMethods() {
public Set<HttpMethod> getSupportedMethods() {
return supportedMethods;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2017 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.
@@ -21,10 +21,9 @@ import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -89,14 +88,10 @@ public class ResourceWebHandler
implements WebHandler, InitializingBean, SmartInitializingSingleton {
/** Set of supported HTTP methods */
private static final Set<String> SUPPORTED_METHODS = new LinkedHashSet<>(2);
private static final Set<HttpMethod> SUPPORTED_METHODS = EnumSet.of(HttpMethod.GET, HttpMethod.HEAD);
private static final Log logger = LogFactory.getLog(ResourceWebHandler.class);
static {
SUPPORTED_METHODS.addAll(Arrays.asList("GET", "HEAD"));
}
private final List<Resource> locations = new ArrayList<>(4);
@@ -294,9 +289,9 @@ public class ResourceWebHandler
}
// Supported methods and required session
String httpMehtod = exchange.getRequest().getMethod().name();
if (!SUPPORTED_METHODS.contains(httpMehtod)) {
return Mono.error(new MethodNotAllowedException(httpMehtod, SUPPORTED_METHODS));
HttpMethod httpMethod = exchange.getRequest().getMethod();
if (!SUPPORTED_METHODS.contains(httpMethod)) {
return Mono.error(new MethodNotAllowedException(httpMethod, SUPPORTED_METHODS));
}
// Header phase

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2017 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.
@@ -20,6 +20,7 @@ import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
@@ -218,12 +219,12 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe
if (helper.hasMethodsMismatch()) {
HttpMethod httpMethod = request.getMethod();
Set<String> methods = helper.getAllowedMethods();
Set<HttpMethod> methods = helper.getAllowedMethods();
if (HttpMethod.OPTIONS.matches(httpMethod.name())) {
HttpOptionsHandler handler = new HttpOptionsHandler(methods);
return new HandlerMethod(handler, HTTP_OPTIONS_HANDLE_METHOD);
}
throw new MethodNotAllowedException(httpMethod.name(), methods);
throw new MethodNotAllowedException(httpMethod, methods);
}
if (helper.hasConsumesMismatch()) {
@@ -280,42 +281,42 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe
* Any partial matches for "methods"?
*/
public boolean hasMethodsMismatch() {
return !this.partialMatches.stream().
filter(PartialMatch::hasMethodsMatch).findAny().isPresent();
return this.partialMatches.stream().
noneMatch(PartialMatch::hasMethodsMatch);
}
/**
* Any partial matches for "methods" and "consumes"?
*/
public boolean hasConsumesMismatch() {
return !this.partialMatches.stream().
filter(PartialMatch::hasConsumesMatch).findAny().isPresent();
return this.partialMatches.stream().
noneMatch(PartialMatch::hasConsumesMatch);
}
/**
* Any partial matches for "methods", "consumes", and "produces"?
*/
public boolean hasProducesMismatch() {
return !this.partialMatches.stream().
filter(PartialMatch::hasProducesMatch).findAny().isPresent();
return this.partialMatches.stream().
noneMatch(PartialMatch::hasProducesMatch);
}
/**
* Any partial matches for "methods", "consumes", "produces", and "params"?
*/
public boolean hasParamsMismatch() {
return !this.partialMatches.stream().
filter(PartialMatch::hasParamsMatch).findAny().isPresent();
return this.partialMatches.stream().
noneMatch(PartialMatch::hasParamsMatch);
}
/**
* Return declared HTTP methods.
*/
public Set<String> getAllowedMethods() {
public Set<HttpMethod> getAllowedMethods() {
return this.partialMatches.stream().
flatMap(m -> m.getInfo().getMethodsCondition().getMethods().stream()).
map(requestMethod -> requestMethod.name()).
collect(Collectors.toCollection(LinkedHashSet::new));
map(requestMethod -> HttpMethod.resolve(requestMethod.name())).
collect(Collectors.toSet());
}
/**
@@ -413,29 +414,23 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe
private final HttpHeaders headers = new HttpHeaders();
public HttpOptionsHandler(Set<String> declaredMethods) {
public HttpOptionsHandler(Set<HttpMethod> declaredMethods) {
this.headers.setAllow(initAllowedHttpMethods(declaredMethods));
}
private static Set<HttpMethod> initAllowedHttpMethods(Set<String> declaredMethods) {
Set<HttpMethod> result = new LinkedHashSet<>(declaredMethods.size());
private static Set<HttpMethod> initAllowedHttpMethods(Set<HttpMethod> declaredMethods) {
if (declaredMethods.isEmpty()) {
for (HttpMethod method : HttpMethod.values()) {
if (!HttpMethod.TRACE.equals(method)) {
result.add(method);
}
}
return EnumSet.allOf(HttpMethod.class).stream()
.filter(method -> !method.equals(HttpMethod.TRACE))
.collect(Collectors.toSet());
}
else {
boolean hasHead = declaredMethods.contains("HEAD");
for (String method : declaredMethods) {
result.add(HttpMethod.valueOf(method));
if (!hasHead && "GET".equals(method)) {
result.add(HttpMethod.HEAD);
}
Set<HttpMethod> result = new LinkedHashSet<>(declaredMethods);
if (result.contains(HttpMethod.GET)) {
result.add(HttpMethod.HEAD);
}
return result;
}
return result;
}
@SuppressWarnings("unused")

View File

@@ -187,7 +187,7 @@ public class HandshakeWebSocketService implements WebSocketService, Lifecycle {
}
if (HttpMethod.GET != method) {
return Mono.error(new MethodNotAllowedException(method.name(), Collections.singleton("GET")));
return Mono.error(new MethodNotAllowedException(method, Collections.singleton(HttpMethod.GET)));
}
if (!"WebSocket".equalsIgnoreCase(headers.getUpgrade())) {

View File

@@ -20,6 +20,7 @@ import java.lang.reflect.Method;
import java.net.URI;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
@@ -56,11 +57,7 @@ import org.springframework.web.server.UnsupportedMediaTypeStatusException;
import org.springframework.web.server.support.HttpRequestPathHelper;
import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.*;
import static org.springframework.mock.http.server.reactive.test.MockServerHttpRequest.get;
import static org.springframework.web.bind.annotation.RequestMethod.GET;
import static org.springframework.web.bind.annotation.RequestMethod.HEAD;
@@ -141,7 +138,7 @@ public class RequestMappingInfoHandlerMappingTests {
Mono<Object> mono = this.handlerMapping.getHandler(exchange);
assertError(mono, MethodNotAllowedException.class,
ex -> assertEquals(new HashSet<>(Arrays.asList("GET", "HEAD")), ex.getSupportedMethods()));
ex -> assertEquals(EnumSet.of(HttpMethod.GET, HttpMethod.HEAD), ex.getSupportedMethods()));
}
@Test // SPR-9603
@@ -192,10 +189,10 @@ public class RequestMappingInfoHandlerMappingTests {
@Test
public void getHandlerHttpOptions() throws Exception {
testHttpOptions("/foo", "GET,HEAD");
testHttpOptions("/person/1", "PUT");
testHttpOptions("/persons", "GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS");
testHttpOptions("/something", "PUT,POST");
testHttpOptions("/foo", EnumSet.of(HttpMethod.GET, HttpMethod.HEAD));
testHttpOptions("/person/1", EnumSet.of(HttpMethod.PUT));
testHttpOptions("/persons", EnumSet.of(HttpMethod.GET, HttpMethod.HEAD, HttpMethod.POST, HttpMethod.PUT, HttpMethod.PATCH, HttpMethod.DELETE, HttpMethod.OPTIONS));
testHttpOptions("/something", EnumSet.of(HttpMethod.PUT, HttpMethod.POST));
}
@Test
@@ -349,7 +346,7 @@ public class RequestMappingInfoHandlerMappingTests {
ex.getSupportedMediaTypes()));
}
private void testHttpOptions(String requestURI, String allowHeader) throws Exception {
private void testHttpOptions(String requestURI, Set<HttpMethod> allowedMethods) throws Exception {
ServerWebExchange exchange = MockServerHttpRequest.options(requestURI).toExchange();
HandlerMethod handlerMethod = (HandlerMethod) this.handlerMapping.getHandler(exchange).block();
@@ -363,7 +360,7 @@ public class RequestMappingInfoHandlerMappingTests {
Optional<Object> value = result.getReturnValue();
assertTrue(value.isPresent());
assertEquals(HttpHeaders.class, value.get().getClass());
assertEquals(allowHeader, ((HttpHeaders) value.get()).getFirst("Allow"));
assertEquals(allowedMethods, ((HttpHeaders) value.get()).getAllow());
}
private void testMediaTypeNotAcceptable(String url) throws Exception {