parent
06e1cc2f9b
commit
5d0f49c2c8
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
|
@ -31,11 +31,10 @@ import org.springframework.validation.FieldError;
|
|||
import org.springframework.validation.ObjectError;
|
||||
import org.springframework.web.server.ServerWebInputException;
|
||||
|
||||
|
||||
/**
|
||||
* A specialization of {@link ServerWebInputException} thrown when after data
|
||||
* binding and validation failure. Implements {@link BindingResult} (and its
|
||||
* super-interface {@link Errors}) to allow for direct analysis of binding and
|
||||
* validation errors.
|
||||
* {@link ServerWebInputException} subclass that indicates a data binding or
|
||||
* validation failure.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 5.0
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright 2002-2022 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.server;
|
||||
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
|
||||
|
||||
/**
|
||||
* {@link ServerWebInputException} subclass that indicates a missing request
|
||||
* value such as a request header, cookie value, query parameter, etc.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 6.0
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class MissingRequestValueException extends ServerWebInputException {
|
||||
|
||||
private final String name;
|
||||
|
||||
private final Class<?> type;
|
||||
|
||||
private final String label;
|
||||
|
||||
|
||||
public MissingRequestValueException(String name, Class<?> type, String label, MethodParameter parameter) {
|
||||
super("Required " + label + " '" + name + "' is not present.", parameter);
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.label = label;
|
||||
getBody().withDetail(getReason());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the name of the missing value, e.g. the name of the missing request
|
||||
* header, or cookie, etc.
|
||||
*/
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the target type the value is converted when present.
|
||||
*/
|
||||
public Class<?> getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a label that describes the request value, e.g. "request header",
|
||||
* "cookie value", etc. Use this to create a custom message.
|
||||
*/
|
||||
public String getLabel() {
|
||||
return this.label;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright 2002-2022 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.server;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
* {@link ServerWebInputException} subclass that indicates an unsatisfied
|
||||
* parameter condition, as typically expressed using an {@code @RequestMapping}
|
||||
* annotation at the {@code @Controller} type level.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 6.0
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class UnsatisfiedRequestParameterException extends ServerWebInputException {
|
||||
|
||||
private final List<String> conditions;
|
||||
|
||||
private final MultiValueMap<String, String> requestParams;
|
||||
|
||||
|
||||
public UnsatisfiedRequestParameterException(
|
||||
List<String> conditions, MultiValueMap<String, String> requestParams) {
|
||||
|
||||
super(initReason(conditions, requestParams));
|
||||
this.conditions = conditions;
|
||||
this.requestParams = requestParams;
|
||||
getBody().withDetail("Invalid request parameters.");
|
||||
}
|
||||
|
||||
private static String initReason(List<String> conditions, MultiValueMap<String, String> queryParams) {
|
||||
StringBuilder sb = new StringBuilder("Parameter conditions ");
|
||||
int i = 0;
|
||||
for (String condition : conditions) {
|
||||
if (i > 0) {
|
||||
sb.append(" OR ");
|
||||
}
|
||||
sb.append('"').append(condition).append('"');
|
||||
i++;
|
||||
}
|
||||
sb.append(" not met for actual request parameters: ").append(queryParams);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return String representations of the unsatisfied condition(s).
|
||||
*/
|
||||
public List<String> getConditions() {
|
||||
return this.conditions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the actual request parameters.
|
||||
*/
|
||||
public MultiValueMap<String, String> getRequestParams() {
|
||||
return this.requestParams;
|
||||
}
|
||||
|
||||
}
|
|
@ -29,6 +29,7 @@ import org.springframework.http.HttpStatus;
|
|||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ProblemDetail;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.validation.FieldError;
|
||||
|
@ -43,7 +44,9 @@ import org.springframework.web.bind.support.WebExchangeBindException;
|
|||
import org.springframework.web.context.request.async.AsyncRequestTimeoutException;
|
||||
import org.springframework.web.multipart.support.MissingServletRequestPartException;
|
||||
import org.springframework.web.server.MethodNotAllowedException;
|
||||
import org.springframework.web.server.MissingRequestValueException;
|
||||
import org.springframework.web.server.NotAcceptableStatusException;
|
||||
import org.springframework.web.server.UnsatisfiedRequestParameterException;
|
||||
import org.springframework.web.server.UnsupportedMediaTypeStatusException;
|
||||
import org.springframework.web.testfixture.method.ResolvableMethod;
|
||||
|
||||
|
@ -288,6 +291,29 @@ public class ErrorResponseExceptionTests {
|
|||
assertThat(ex.getHeaders()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void missingRequestValueException() {
|
||||
|
||||
ErrorResponse ex = new MissingRequestValueException(
|
||||
"foo", String.class, "header", this.methodParameter);
|
||||
|
||||
assertStatus(ex, HttpStatus.BAD_REQUEST);
|
||||
assertDetail(ex, "Required header 'foo' is not present.");
|
||||
assertThat(ex.getHeaders()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void unsatisfiedRequestParameterException() {
|
||||
|
||||
ErrorResponse ex = new UnsatisfiedRequestParameterException(
|
||||
Arrays.asList("foo=bar", "bar=baz"),
|
||||
new LinkedMultiValueMap<>(Collections.singletonMap("q", Arrays.asList("1", "2"))));
|
||||
|
||||
assertStatus(ex, HttpStatus.BAD_REQUEST);
|
||||
assertDetail(ex, "Invalid request parameters.");
|
||||
assertThat(ex.getHeaders()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void webExchangeBindException() {
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
|
@ -46,6 +46,7 @@ import org.springframework.web.server.MethodNotAllowedException;
|
|||
import org.springframework.web.server.NotAcceptableStatusException;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.ServerWebInputException;
|
||||
import org.springframework.web.server.UnsatisfiedRequestParameterException;
|
||||
import org.springframework.web.server.UnsupportedMediaTypeStatusException;
|
||||
import org.springframework.web.util.pattern.PathPattern;
|
||||
|
||||
|
@ -190,7 +191,8 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe
|
|||
catch (InvalidMediaTypeException ex) {
|
||||
throw new UnsupportedMediaTypeStatusException(ex.getMessage());
|
||||
}
|
||||
throw new UnsupportedMediaTypeStatusException(contentType, new ArrayList<>(mediaTypes), exchange.getRequest().getMethod());
|
||||
throw new UnsupportedMediaTypeStatusException(
|
||||
contentType, new ArrayList<>(mediaTypes), exchange.getRequest().getMethod());
|
||||
}
|
||||
|
||||
if (helper.hasProducesMismatch()) {
|
||||
|
@ -199,9 +201,9 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe
|
|||
}
|
||||
|
||||
if (helper.hasParamsMismatch()) {
|
||||
throw new ServerWebInputException(
|
||||
"Expected parameters: " + helper.getParamConditions() +
|
||||
", actual query parameters: " + request.getQueryParams());
|
||||
throw new UnsatisfiedRequestParameterException(
|
||||
helper.getParamConditions().stream().map(Object::toString).toList(),
|
||||
request.getQueryParams());
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -217,10 +219,9 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe
|
|||
|
||||
|
||||
public PartialMatchHelper(Set<RequestMappingInfo> infos, ServerWebExchange exchange) {
|
||||
this.partialMatches.addAll(infos.stream().
|
||||
filter(info -> info.getPatternsCondition().getMatchingCondition(exchange) != null).
|
||||
map(info -> new PartialMatch(info, exchange)).
|
||||
collect(Collectors.toList()));
|
||||
this.partialMatches.addAll(infos.stream()
|
||||
.filter(info -> info.getPatternsCondition().getMatchingCondition(exchange) != null)
|
||||
.map(info -> new PartialMatch(info, exchange)).toList());
|
||||
}
|
||||
|
||||
|
||||
|
@ -235,42 +236,38 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe
|
|||
* Any partial matches for "methods"?
|
||||
*/
|
||||
public boolean hasMethodsMismatch() {
|
||||
return this.partialMatches.stream().
|
||||
noneMatch(PartialMatch::hasMethodsMatch);
|
||||
return this.partialMatches.stream().noneMatch(PartialMatch::hasMethodsMatch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Any partial matches for "methods" and "consumes"?
|
||||
*/
|
||||
public boolean hasConsumesMismatch() {
|
||||
return this.partialMatches.stream().
|
||||
noneMatch(PartialMatch::hasConsumesMatch);
|
||||
return this.partialMatches.stream().noneMatch(PartialMatch::hasConsumesMatch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Any partial matches for "methods", "consumes", and "produces"?
|
||||
*/
|
||||
public boolean hasProducesMismatch() {
|
||||
return this.partialMatches.stream().
|
||||
noneMatch(PartialMatch::hasProducesMatch);
|
||||
return this.partialMatches.stream().noneMatch(PartialMatch::hasProducesMatch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Any partial matches for "methods", "consumes", "produces", and "params"?
|
||||
*/
|
||||
public boolean hasParamsMismatch() {
|
||||
return this.partialMatches.stream().
|
||||
noneMatch(PartialMatch::hasParamsMatch);
|
||||
return this.partialMatches.stream().noneMatch(PartialMatch::hasParamsMatch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return declared HTTP methods.
|
||||
*/
|
||||
public Set<HttpMethod> getAllowedMethods() {
|
||||
return this.partialMatches.stream().
|
||||
flatMap(m -> m.getInfo().getMethodsCondition().getMethods().stream()).
|
||||
map(requestMethod -> HttpMethod.valueOf(requestMethod.name())).
|
||||
collect(Collectors.toSet());
|
||||
return this.partialMatches.stream()
|
||||
.flatMap(m -> m.getInfo().getMethodsCondition().getMethods().stream())
|
||||
.map(requestMethod -> HttpMethod.valueOf(requestMethod.name()))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -278,9 +275,10 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe
|
|||
* match the "methods" condition.
|
||||
*/
|
||||
public Set<MediaType> getConsumableMediaTypes() {
|
||||
return this.partialMatches.stream().filter(PartialMatch::hasMethodsMatch).
|
||||
flatMap(m -> m.getInfo().getConsumesCondition().getConsumableMediaTypes().stream()).
|
||||
collect(Collectors.toCollection(LinkedHashSet::new));
|
||||
return this.partialMatches.stream()
|
||||
.filter(PartialMatch::hasMethodsMatch)
|
||||
.flatMap(m -> m.getInfo().getConsumesCondition().getConsumableMediaTypes().stream())
|
||||
.collect(Collectors.toCollection(LinkedHashSet::new));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -288,9 +286,10 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe
|
|||
* match the "methods" and "consumes" conditions.
|
||||
*/
|
||||
public Set<MediaType> getProducibleMediaTypes() {
|
||||
return this.partialMatches.stream().filter(PartialMatch::hasConsumesMatch).
|
||||
flatMap(m -> m.getInfo().getProducesCondition().getProducibleMediaTypes().stream()).
|
||||
collect(Collectors.toCollection(LinkedHashSet::new));
|
||||
return this.partialMatches.stream()
|
||||
.filter(PartialMatch::hasConsumesMatch)
|
||||
.flatMap(m -> m.getInfo().getProducesCondition().getProducibleMediaTypes().stream())
|
||||
.collect(Collectors.toCollection(LinkedHashSet::new));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -298,9 +297,10 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe
|
|||
* match the "methods", "consumes", and "params" conditions.
|
||||
*/
|
||||
public List<Set<NameValueExpression<String>>> getParamConditions() {
|
||||
return this.partialMatches.stream().filter(PartialMatch::hasProducesMatch).
|
||||
map(match -> match.getInfo().getParamsCondition().getExpressions()).
|
||||
collect(Collectors.toList());
|
||||
return this.partialMatches.stream()
|
||||
.filter(PartialMatch::hasProducesMatch)
|
||||
.map(match -> match.getInfo().getParamsCondition().getExpressions())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
|
@ -225,8 +225,14 @@ public abstract class AbstractMessageReaderArgumentResolver extends HandlerMetho
|
|||
}
|
||||
|
||||
private ServerWebInputException handleMissingBody(MethodParameter parameter) {
|
||||
String paramInfo = parameter.getExecutable().toGenericString();
|
||||
return new ServerWebInputException("Request body is missing: " + paramInfo, parameter);
|
||||
|
||||
DecodingException cause = new DecodingException(
|
||||
"No request body for: " + parameter.getExecutable().toGenericString());
|
||||
|
||||
ServerWebInputException ex = new ServerWebInputException("No request body", parameter, cause);
|
||||
ex.setDetail("Invalid request content");
|
||||
|
||||
return ex;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
|
@ -34,6 +34,7 @@ import org.springframework.web.bind.WebDataBinder;
|
|||
import org.springframework.web.bind.annotation.ValueConstants;
|
||||
import org.springframework.web.reactive.BindingContext;
|
||||
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolverSupport;
|
||||
import org.springframework.web.server.MissingRequestValueException;
|
||||
import org.springframework.web.server.ServerErrorException;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.ServerWebInputException;
|
||||
|
@ -244,9 +245,8 @@ public abstract class AbstractNamedValueArgumentResolver extends HandlerMethodAr
|
|||
* @param parameter the method parameter
|
||||
*/
|
||||
protected void handleMissingValue(String name, MethodParameter parameter) {
|
||||
String typeName = parameter.getNestedParameterType().getSimpleName();
|
||||
throw new ServerWebInputException("Missing argument '" + name + "' for method " +
|
||||
"parameter of type " + typeName, parameter);
|
||||
throw new MissingRequestValueException(
|
||||
name, parameter.getNestedParameterType(), "request value", parameter);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
|
@ -23,8 +23,8 @@ import org.springframework.http.HttpCookie;
|
|||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.bind.annotation.CookieValue;
|
||||
import org.springframework.web.server.MissingRequestValueException;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.ServerWebInputException;
|
||||
|
||||
/**
|
||||
* Resolve method arguments annotated with {@code @CookieValue}.
|
||||
|
@ -76,9 +76,8 @@ public class CookieValueMethodArgumentResolver extends AbstractNamedValueSyncArg
|
|||
|
||||
@Override
|
||||
protected void handleMissingValue(String name, MethodParameter parameter) {
|
||||
String type = parameter.getNestedParameterType().getSimpleName();
|
||||
String reason = "Missing cookie '" + name + "' for method parameter of type " + type;
|
||||
throw new ServerWebInputException(reason, parameter);
|
||||
throw new MissingRequestValueException(
|
||||
name, parameter.getNestedParameterType(), "cookie", parameter);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
|
@ -31,6 +31,7 @@ import org.springframework.util.StringUtils;
|
|||
import org.springframework.web.bind.annotation.MatrixVariable;
|
||||
import org.springframework.web.bind.annotation.ValueConstants;
|
||||
import org.springframework.web.reactive.HandlerMapping;
|
||||
import org.springframework.web.server.MissingRequestValueException;
|
||||
import org.springframework.web.server.ServerErrorException;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.ServerWebInputException;
|
||||
|
@ -120,9 +121,8 @@ public class MatrixVariableMethodArgumentResolver extends AbstractNamedValueSync
|
|||
|
||||
@Override
|
||||
protected void handleMissingValue(String name, MethodParameter parameter) throws ServerWebInputException {
|
||||
String paramInfo = parameter.getNestedParameterType().getSimpleName();
|
||||
throw new ServerWebInputException("Missing matrix variable '" + name + "' " +
|
||||
"for method parameter of type " + paramInfo, parameter);
|
||||
throw new MissingRequestValueException(
|
||||
name, parameter.getNestedParameterType(), "path parameter", parameter);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
|
@ -26,8 +26,8 @@ import org.springframework.lang.Nullable;
|
|||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.bind.annotation.RequestAttribute;
|
||||
import org.springframework.web.bind.annotation.ValueConstants;
|
||||
import org.springframework.web.server.MissingRequestValueException;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.ServerWebInputException;
|
||||
|
||||
/**
|
||||
* Resolves method arguments annotated with an @{@link RequestAttribute}.
|
||||
|
@ -90,9 +90,8 @@ public class RequestAttributeMethodArgumentResolver extends AbstractNamedValueSy
|
|||
|
||||
@Override
|
||||
protected void handleMissingValue(String name, MethodParameter parameter) {
|
||||
String type = parameter.getNestedParameterType().getSimpleName();
|
||||
String reason = "Missing request attribute '" + name + "' of type " + type;
|
||||
throw new ServerWebInputException(reason, parameter);
|
||||
throw new MissingRequestValueException(
|
||||
name, parameter.getNestedParameterType(), "request attribute", parameter);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
|
@ -26,8 +26,8 @@ import org.springframework.core.convert.ConversionService;
|
|||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.server.MissingRequestValueException;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.ServerWebInputException;
|
||||
|
||||
/**
|
||||
* Resolves method arguments annotated with {@code @RequestHeader} except for
|
||||
|
@ -89,9 +89,8 @@ public class RequestHeaderMethodArgumentResolver extends AbstractNamedValueSyncA
|
|||
|
||||
@Override
|
||||
protected void handleMissingValue(String name, MethodParameter parameter) {
|
||||
String type = parameter.getNestedParameterType().getSimpleName();
|
||||
throw new ServerWebInputException("Missing request header '" + name + "' " +
|
||||
"for method parameter of type " + type, parameter);
|
||||
throw new MissingRequestValueException(
|
||||
name, parameter.getNestedParameterType(), "header", parameter);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
|
@ -28,8 +28,8 @@ import org.springframework.lang.Nullable;
|
|||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ValueConstants;
|
||||
import org.springframework.web.server.MissingRequestValueException;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.ServerWebInputException;
|
||||
|
||||
/**
|
||||
* Resolver for method arguments annotated with @{@link RequestParam} from URI
|
||||
|
@ -109,9 +109,8 @@ public class RequestParamMethodArgumentResolver extends AbstractNamedValueSyncAr
|
|||
|
||||
@Override
|
||||
protected void handleMissingValue(String name, MethodParameter parameter, ServerWebExchange exchange) {
|
||||
String type = parameter.getNestedParameterType().getSimpleName();
|
||||
String reason = "Required " + type + " parameter '" + name + "' is not present";
|
||||
throw new ServerWebInputException(reason, parameter);
|
||||
throw new MissingRequestValueException(
|
||||
name, parameter.getNestedParameterType(), "query parameter", parameter);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -37,8 +37,8 @@ import org.springframework.util.CollectionUtils;
|
|||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.RequestPart;
|
||||
import org.springframework.web.reactive.BindingContext;
|
||||
import org.springframework.web.server.MissingRequestValueException;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.ServerWebInputException;
|
||||
|
||||
/**
|
||||
* Resolver for {@code @RequestPart} arguments where the named part is decoded
|
||||
|
@ -115,8 +115,8 @@ public class RequestPartMethodArgumentResolver extends AbstractMessageReaderArgu
|
|||
List<Part> list = map.get(name);
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
if (isRequired) {
|
||||
String reason = "Required request part '" + name + "' is not present";
|
||||
throw new ServerWebInputException(reason, parameter);
|
||||
throw new MissingRequestValueException(
|
||||
name, parameter.getParameterType(), "request part", parameter);
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
|
@ -24,8 +24,8 @@ import org.springframework.core.ReactiveAdapterRegistry;
|
|||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.bind.annotation.SessionAttribute;
|
||||
import org.springframework.web.bind.annotation.ValueConstants;
|
||||
import org.springframework.web.server.MissingRequestValueException;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.ServerWebInputException;
|
||||
|
||||
/**
|
||||
* Resolves method arguments annotated with an @{@link SessionAttribute}.
|
||||
|
@ -62,9 +62,8 @@ public class SessionAttributeMethodArgumentResolver extends AbstractNamedValueAr
|
|||
|
||||
@Override
|
||||
protected void handleMissingValue(String name, MethodParameter parameter) {
|
||||
String type = parameter.getNestedParameterType().getSimpleName();
|
||||
String reason = "Missing session attribute '" + name + "' of type " + type;
|
||||
throw new ServerWebInputException(reason, parameter);
|
||||
throw new MissingRequestValueException(
|
||||
name, parameter.getNestedParameterType(), "session attribute", parameter);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ import org.springframework.web.reactive.result.method.RequestMappingInfo.Builder
|
|||
import org.springframework.web.server.MethodNotAllowedException;
|
||||
import org.springframework.web.server.NotAcceptableStatusException;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.ServerWebInputException;
|
||||
import org.springframework.web.server.UnsatisfiedRequestParameterException;
|
||||
import org.springframework.web.server.UnsupportedMediaTypeStatusException;
|
||||
import org.springframework.web.testfixture.http.server.reactive.MockServerHttpRequest;
|
||||
import org.springframework.web.testfixture.server.MockServerWebExchange;
|
||||
|
@ -182,7 +182,7 @@ public class RequestMappingInfoHandlerMappingTests {
|
|||
public void getHandlerTestRequestParamMismatch() {
|
||||
ServerWebExchange exchange = MockServerWebExchange.from(get("/params"));
|
||||
Mono<Object> mono = this.handlerMapping.getHandler(exchange);
|
||||
assertError(mono, ServerWebInputException.class, ex -> {
|
||||
assertError(mono, UnsatisfiedRequestParameterException.class, ex -> {
|
||||
assertThat(ex.getReason()).contains("[foo=bar]");
|
||||
assertThat(ex.getReason()).contains("[bar=baz]");
|
||||
});
|
||||
|
@ -212,7 +212,9 @@ public class RequestMappingInfoHandlerMappingTests {
|
|||
exchange = MockServerWebExchange.from(get("/content").accept(MediaType.APPLICATION_JSON));
|
||||
this.handlerMapping.getHandler(exchange).block();
|
||||
|
||||
assertThat(exchange.getAttributes().get(name)).as("Negated expression shouldn't be listed as producible type").isNull();
|
||||
assertThat(exchange.getAttributes().get(name))
|
||||
.as("Negated expression shouldn't be listed as producible type")
|
||||
.isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -352,7 +354,9 @@ public class RequestMappingInfoHandlerMappingTests {
|
|||
ServerWebExchange exchange = MockServerWebExchange.from(request);
|
||||
Mono<Object> mono = this.handlerMapping.getHandler(exchange);
|
||||
|
||||
assertError(mono, UnsupportedMediaTypeStatusException.class, ex -> assertThat(ex.getSupportedMediaTypes()).as("Invalid supported consumable media types").isEqualTo(Collections.singletonList(new MediaType("application", "xml"))));
|
||||
assertError(mono, UnsupportedMediaTypeStatusException.class, ex -> assertThat(ex.getSupportedMediaTypes())
|
||||
.as("Invalid supported consumable media types")
|
||||
.isEqualTo(Collections.singletonList(new MediaType("application", "xml"))));
|
||||
}
|
||||
|
||||
private void testHttpOptions(String requestURI, Set<HttpMethod> allowedMethods, @Nullable MediaType acceptPatch) {
|
||||
|
@ -382,7 +386,9 @@ public class RequestMappingInfoHandlerMappingTests {
|
|||
ServerWebExchange exchange = MockServerWebExchange.from(get(url).accept(MediaType.APPLICATION_JSON));
|
||||
Mono<Object> mono = this.handlerMapping.getHandler(exchange);
|
||||
|
||||
assertError(mono, NotAcceptableStatusException.class, ex -> assertThat(ex.getSupportedMediaTypes()).as("Invalid supported producible media types").isEqualTo(Collections.singletonList(new MediaType("application", "xml"))));
|
||||
assertError(mono, NotAcceptableStatusException.class, ex -> assertThat(ex.getSupportedMediaTypes())
|
||||
.as("Invalid supported producible media types")
|
||||
.isEqualTo(Collections.singletonList(new MediaType("application", "xml"))));
|
||||
}
|
||||
|
||||
private void handleMatch(ServerWebExchange exchange, String pattern) {
|
||||
|
|
Loading…
Reference in New Issue