Add WebInputException subclasses

Closes gh-28142
This commit is contained in:
rstoyanchev 2022-05-09 08:58:31 +01:00
parent 06e1cc2f9b
commit 5d0f49c2c8
15 changed files with 261 additions and 79 deletions

View File

@ -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

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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() {

View File

@ -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());
}
/**

View File

@ -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;
}
/**

View File

@ -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);
}
/**

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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);
}
}

View File

@ -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) {