Apply new ResponseStatusException hierarchy

This commit replaces use of the existing ServletException-based
exceptions with the new ones from ~.web.server.
This commit is contained in:
Rossen Stoyanchev
2016-04-19 15:58:24 -04:00
parent 3849fd6b5b
commit 6b7360fed1
18 changed files with 95 additions and 125 deletions

View File

@@ -1,30 +0,0 @@
/*
* Copyright 2002-2015 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
*
* http://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.reactive;
import org.springframework.core.NestedRuntimeException;
/**
* @author Rossen Stoyanchev
*/
public class HandlerNotFoundException extends NestedRuntimeException {
public HandlerNotFoundException() {
super("No handler found.");
}
}

View File

@@ -29,7 +29,7 @@ import org.springframework.http.MediaType;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.server.NotAcceptableStatusException;
import org.springframework.web.server.ServerWebExchange;
/**
@@ -85,7 +85,7 @@ public abstract class AbstractMappingContentTypeResolver implements MappingConte
@Override
public List<MediaType> resolveMediaTypes(ServerWebExchange exchange)
throws HttpMediaTypeNotAcceptableException {
throws NotAcceptableStatusException {
String key = extractKey(exchange);
return resolveMediaTypes(key);
@@ -95,11 +95,9 @@ public abstract class AbstractMappingContentTypeResolver implements MappingConte
* An overloaded resolve method with a pre-resolved lookup key.
* @param key the key for looking up media types
* @return a list of resolved media types or an empty list
* @throws HttpMediaTypeNotAcceptableException
* @throws NotAcceptableStatusException
*/
public List<MediaType> resolveMediaTypes(String key)
throws HttpMediaTypeNotAcceptableException {
public List<MediaType> resolveMediaTypes(String key) throws NotAcceptableStatusException {
if (StringUtils.hasText(key)) {
MediaType mediaType = getMediaType(key);
if (mediaType != null) {
@@ -139,7 +137,7 @@ public abstract class AbstractMappingContentTypeResolver implements MappingConte
* this method it will be added to the mappings.
*/
@SuppressWarnings("UnusedParameters")
protected MediaType handleNoMatch(String key) throws HttpMediaTypeNotAcceptableException {
protected MediaType handleNoMatch(String key) throws NotAcceptableStatusException {
return null;
}

View File

@@ -23,7 +23,7 @@ import java.util.Set;
import org.springframework.http.MediaType;
import org.springframework.util.Assert;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.server.NotAcceptableStatusException;
import org.springframework.web.server.ServerWebExchange;
/**
@@ -71,7 +71,7 @@ public class CompositeContentTypeResolver implements MappingContentTypeResolver
@Override
public List<MediaType> resolveMediaTypes(ServerWebExchange exchange) throws HttpMediaTypeNotAcceptableException {
public List<MediaType> resolveMediaTypes(ServerWebExchange exchange) throws NotAcceptableStatusException {
for (ContentTypeResolver resolver : this.resolvers) {
List<MediaType> mediaTypes = resolver.resolveMediaTypes(exchange);
if (mediaTypes.isEmpty() || (mediaTypes.size() == 1 && mediaTypes.contains(MediaType.ALL))) {

View File

@@ -18,7 +18,7 @@ package org.springframework.web.reactive.accept;
import java.util.List;
import org.springframework.http.MediaType;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.server.NotAcceptableStatusException;
import org.springframework.web.server.ServerWebExchange;
/**
@@ -34,9 +34,8 @@ public interface ContentTypeResolver {
* @param exchange the current exchange
* @return the requested media types or an empty list
*
* @throws HttpMediaTypeNotAcceptableException if the requested media
* types cannot be parsed
* @throws NotAcceptableStatusException if the requested media types is invalid
*/
List<MediaType> resolveMediaTypes(ServerWebExchange exchange) throws HttpMediaTypeNotAcceptableException;
List<MediaType> resolveMediaTypes(ServerWebExchange exchange) throws NotAcceptableStatusException;
}

View File

@@ -19,7 +19,7 @@ import java.util.List;
import org.springframework.http.InvalidMediaTypeException;
import org.springframework.http.MediaType;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.server.NotAcceptableStatusException;
import org.springframework.web.server.ServerWebExchange;
/**
@@ -30,9 +30,7 @@ import org.springframework.web.server.ServerWebExchange;
public class HeaderContentTypeResolver implements ContentTypeResolver {
@Override
public List<MediaType> resolveMediaTypes(ServerWebExchange exchange)
throws HttpMediaTypeNotAcceptableException {
public List<MediaType> resolveMediaTypes(ServerWebExchange exchange) throws NotAcceptableStatusException {
try {
List<MediaType> mediaTypes = exchange.getRequest().getHeaders().getAccept();
MediaType.sortBySpecificityAndQuality(mediaTypes);
@@ -40,8 +38,9 @@ public class HeaderContentTypeResolver implements ContentTypeResolver {
}
catch (InvalidMediaTypeException ex) {
String value = exchange.getRequest().getHeaders().getFirst("Accept");
throw new HttpMediaTypeNotAcceptableException(
throw new NotAcceptableStatusException(
"Could not parse 'Accept' header [" + value + "]: " + ex.getMessage());
}
}
}

View File

@@ -23,7 +23,7 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.http.MediaType;
import org.springframework.util.Assert;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.server.NotAcceptableStatusException;
import org.springframework.web.server.ServerWebExchange;
/**
@@ -75,8 +75,8 @@ public class ParameterContentTypeResolver extends AbstractMappingContentTypeReso
}
@Override
protected MediaType handleNoMatch(String key) throws HttpMediaTypeNotAcceptableException {
throw new HttpMediaTypeNotAcceptableException(getMediaTypes());
protected MediaType handleNoMatch(String key) throws NotAcceptableStatusException {
throw new NotAcceptableStatusException(getMediaTypes());
}
}

View File

@@ -31,8 +31,7 @@ import org.springframework.http.MediaType;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.accept.PathExtensionContentNegotiationStrategy;
import org.springframework.web.server.NotAcceptableStatusException;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.WebUtils;
@@ -49,11 +48,10 @@ import org.springframework.web.util.WebUtils;
*/
public class PathExtensionContentTypeResolver extends AbstractMappingContentTypeResolver {
private static final Log logger = LogFactory.getLog(PathExtensionContentNegotiationStrategy.class);
private static final Log logger = LogFactory.getLog(PathExtensionContentTypeResolver.class);
private static final boolean JAF_PRESENT = ClassUtils.isPresent(
"javax.activation.FileTypeMap",
PathExtensionContentNegotiationStrategy.class.getClassLoader());
private static final boolean JAF_PRESENT = ClassUtils.isPresent("javax.activation.FileTypeMap",
PathExtensionContentTypeResolver.class.getClassLoader());
private boolean useJaf = true;
@@ -104,7 +102,7 @@ public class PathExtensionContentTypeResolver extends AbstractMappingContentType
}
@Override
protected MediaType handleNoMatch(String key) throws HttpMediaTypeNotAcceptableException {
protected MediaType handleNoMatch(String key) throws NotAcceptableStatusException {
if (this.useJaf && JAF_PRESENT) {
MediaType mediaType = JafMediaTypeFactory.getMediaType("file." + key);
if (mediaType != null && !MediaType.APPLICATION_OCTET_STREAM.equals(mediaType)) {
@@ -112,7 +110,7 @@ public class PathExtensionContentTypeResolver extends AbstractMappingContentType
}
}
if (!this.ignoreUnknownExtensions) {
throw new HttpMediaTypeNotAcceptableException(getMediaTypes());
throw new NotAcceptableStatusException(getMediaTypes());
}
return null;
}

View File

@@ -20,9 +20,10 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.http.MediaType;
import org.springframework.web.HttpMediaTypeException;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.server.NotAcceptableStatusException;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.UnsupportedMediaTypeStatusException;
/**
* Supports media type expressions as described in:
@@ -72,12 +73,16 @@ abstract class AbstractMediaTypeExpression implements Comparable<AbstractMediaTy
boolean match = matchMediaType(exchange);
return (!this.isNegated == match);
}
catch (HttpMediaTypeException ex) {
catch (NotAcceptableStatusException ex) {
return false;
}
catch (UnsupportedMediaTypeStatusException ex) {
return false;
}
}
protected abstract boolean matchMediaType(ServerWebExchange exchange) throws HttpMediaTypeException;
protected abstract boolean matchMediaType(ServerWebExchange exchange)
throws NotAcceptableStatusException, UnsupportedMediaTypeStatusException;
@Override

View File

@@ -26,9 +26,9 @@ import java.util.Set;
import org.springframework.http.InvalidMediaTypeException;
import org.springframework.http.MediaType;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.UnsupportedMediaTypeStatusException;
/**
* A logical disjunction (' || ') request condition to match a request's
@@ -217,14 +217,14 @@ public final class ConsumesRequestCondition extends AbstractRequestCondition<Con
}
@Override
protected boolean matchMediaType(ServerWebExchange exchange) throws HttpMediaTypeNotSupportedException {
protected boolean matchMediaType(ServerWebExchange exchange) throws UnsupportedMediaTypeStatusException {
try {
MediaType contentType = exchange.getRequest().getHeaders().getContentType();
contentType = (contentType != null ? contentType : MediaType.APPLICATION_OCTET_STREAM);
return getMediaType().includes(contentType);
}
catch (InvalidMediaTypeException ex) {
throw new HttpMediaTypeNotSupportedException("Can't parse Content-Type [" +
throw new UnsupportedMediaTypeStatusException("Can't parse Content-Type [" +
exchange.getRequest().getHeaders().getFirst("Content-Type") +
"]: " + ex.getMessage());
}

View File

@@ -25,12 +25,12 @@ import java.util.List;
import java.util.Set;
import org.springframework.http.MediaType;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.accept.ContentNegotiationManager;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.reactive.accept.CompositeContentTypeResolverBuilder;
import org.springframework.web.reactive.accept.ContentTypeResolver;
import org.springframework.web.reactive.accept.HeaderContentTypeResolver;
import org.springframework.web.server.NotAcceptableStatusException;
import org.springframework.web.server.ServerWebExchange;
/**
@@ -234,14 +234,14 @@ public final class ProducesRequestCondition extends AbstractRequestCondition<Pro
}
return 0;
}
catch (HttpMediaTypeNotAcceptableException ex) {
catch (NotAcceptableStatusException ex) {
// should never happen
throw new IllegalStateException("Cannot compare without having any requested media types", ex);
}
}
private List<MediaType> getAcceptedMediaTypes(ServerWebExchange exchange)
throws HttpMediaTypeNotAcceptableException {
throws NotAcceptableStatusException {
List<MediaType> mediaTypes = this.contentTypeResolver.resolveMediaTypes(exchange);
return mediaTypes.isEmpty() ? Collections.singletonList(MediaType.ALL) : mediaTypes;
@@ -306,7 +306,7 @@ public final class ProducesRequestCondition extends AbstractRequestCondition<Pro
}
@Override
protected boolean matchMediaType(ServerWebExchange exchange) throws HttpMediaTypeNotAcceptableException {
protected boolean matchMediaType(ServerWebExchange exchange) throws NotAcceptableStatusException {
List<MediaType> acceptedMediaTypes = getAcceptedMediaTypes(exchange);
for (MediaType acceptedMediaType : acceptedMediaTypes) {
if (getMediaType().isCompatibleWith(acceptedMediaType)) {

View File

@@ -36,16 +36,16 @@ import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.CollectionUtils;
import org.springframework.util.MultiValueMap;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.UnsatisfiedServletRequestParameterException;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.reactive.HandlerMapping;
import org.springframework.web.reactive.result.condition.NameValueExpression;
import org.springframework.web.reactive.result.condition.ParamsRequestCondition;
import org.springframework.web.server.BadRequestStatusException;
import org.springframework.web.server.MethodNotAllowedException;
import org.springframework.web.server.NotAcceptableStatusException;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.UnsupportedMediaTypeStatusException;
import org.springframework.web.util.WebUtils;
/**
@@ -166,10 +166,13 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe
/**
* Iterate all RequestMappingInfos once again, look if any match by URL at
* least and raise exceptions accordingly.
* @throws HttpRequestMethodNotSupportedException if there are matches by URL
* but not by HTTP method
* @throws HttpMediaTypeNotAcceptableException if there are matches by URL
* but not by consumable/producible media types
* @throws MethodNotAllowedException for matches by URL but not by HTTP method
* @throws UnsupportedMediaTypeStatusException if there are matches by URL
* and HTTP method but not by consumable media types
* @throws NotAcceptableStatusException if there are matches by URL and HTTP
* method but not by producible media types
* @throws BadRequestStatusException if there are matches by URL and HTTP
* method but not by query parameter conditions
*/
@Override
protected HandlerMethod handleNoMatch(Set<RequestMappingInfo> requestMappingInfos,
@@ -205,7 +208,7 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe
return new HandlerMethod(handler, HTTP_OPTIONS_HANDLE_METHOD);
}
else if (!allowedMethods.isEmpty()) {
throw new HttpRequestMethodNotSupportedException(httpMethod.name(), allowedMethods);
throw new MethodNotAllowedException(httpMethod.name(), allowedMethods);
}
}
@@ -230,12 +233,12 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe
contentType = request.getHeaders().getContentType();
}
catch (InvalidMediaTypeException ex) {
throw new HttpMediaTypeNotSupportedException(ex.getMessage());
throw new UnsupportedMediaTypeStatusException(ex.getMessage());
}
throw new HttpMediaTypeNotSupportedException(contentType, new ArrayList<>(consumableMediaTypes));
throw new UnsupportedMediaTypeStatusException(contentType, new ArrayList<>(consumableMediaTypes));
}
else if (!producibleMediaTypes.isEmpty()) {
throw new HttpMediaTypeNotAcceptableException(new ArrayList<>(producibleMediaTypes));
throw new NotAcceptableStatusException(new ArrayList<>(producibleMediaTypes));
}
else {
if (!CollectionUtils.isEmpty(paramConditions)) {
@@ -243,7 +246,8 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe
.collect(Collectors.toMap(Entry::getKey,
entry -> entry.getValue().toArray(new String[entry.getValue().size()]))
);
throw new UnsatisfiedServletRequestParameterException(paramConditions, params);
throw new BadRequestStatusException("Unsatisfied query parameter conditions: " +
paramConditions + ", actual: " + params);
}
else {
return null;
@@ -308,7 +312,7 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe
}
private static Set<HttpMethod> initAllowedHttpMethods(Set<String> declaredMethods) {
Set<HttpMethod> result = new LinkedHashSet<HttpMethod>(declaredMethods.size());
Set<HttpMethod> result = new LinkedHashSet<>(declaredMethods.size());
if (declaredMethods.isEmpty()) {
for (HttpMethod method : HttpMethod.values()) {
if (!HttpMethod.TRACE.equals(method)) {

View File

@@ -42,11 +42,11 @@ import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.util.Assert;
import org.springframework.util.MimeType;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.reactive.HandlerResult;
import org.springframework.web.reactive.HandlerResultHandler;
import org.springframework.web.server.NotAcceptableStatusException;
import org.springframework.web.server.ServerWebExchange;
@@ -170,7 +170,7 @@ public class ResponseBodyResultHandler implements HandlerResultHandler, Ordered
}
}
if (compatibleMediaTypes.isEmpty()) {
return Mono.error(new HttpMediaTypeNotAcceptableException(producibleMediaTypes));
return Mono.error(new NotAcceptableStatusException(producibleMediaTypes));
}
List<MediaType> mediaTypes = new ArrayList<>(compatibleMediaTypes);
@@ -200,7 +200,7 @@ public class ResponseBodyResultHandler implements HandlerResultHandler, Ordered
}
}
return Mono.error(new HttpMediaTypeNotAcceptableException(this.allMediaTypes));
return Mono.error(new NotAcceptableStatusException(this.allMediaTypes));
}
private List<MediaType> getAcceptableMediaTypes(ServerHttpRequest request) {