parent
3577e3b758
commit
38d5c0fed6
|
@ -44,6 +44,10 @@ has an `@ExceptionHandler` method that handles any `ErrorResponse` exception, wh
|
|||
includes all built-in web exceptions. You can add more exception handling methods, and
|
||||
use a protected method to map any exception to a `ProblemDetail`.
|
||||
|
||||
You can register `ErrorResponse` interceptors through the
|
||||
xref:web/webflux/config.adoc[WebFlux Config] with a `WebFluxConfigurer`. Use that to intercept
|
||||
any RFC 7807 response and take some action.
|
||||
|
||||
|
||||
|
||||
[[webflux-ann-rest-exceptions-non-standard]]
|
||||
|
|
|
@ -44,6 +44,10 @@ has an `@ExceptionHandler` method that handles any `ErrorResponse` exception, wh
|
|||
includes all built-in web exceptions. You can add more exception handling methods, and
|
||||
use a protected method to map any exception to a `ProblemDetail`.
|
||||
|
||||
You can register `ErrorResponse` interceptors through the
|
||||
xref:web/webmvc/mvc-config.adoc[MVC Config] with a `WebMvcConfigurer`. Use that to intercept
|
||||
any RFC 7807 response and take some action.
|
||||
|
||||
|
||||
|
||||
[[mvc-ann-rest-exceptions-non-standard]]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2024 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.
|
||||
|
@ -333,4 +333,24 @@ public interface ErrorResponse {
|
|||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callback to perform an action before an RFC-7807 {@link ProblemDetail}
|
||||
* response is rendered.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 6.2
|
||||
*/
|
||||
interface Interceptor {
|
||||
|
||||
/**
|
||||
* Handle the given {@code ProblemDetail} that's going to be rendered,
|
||||
* and the {@code ErrorResponse} it originates from, if applicable.
|
||||
* @param detail the {@code ProblemDetail} to be rendered
|
||||
* @param errorResponse the {@code ErrorResponse}, or {@code null} if there isn't one
|
||||
*/
|
||||
void handleError(ProblemDetail detail, @Nullable ErrorResponse errorResponse);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2024 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.
|
||||
|
@ -25,6 +25,7 @@ import org.springframework.http.codec.ServerCodecConfigurer;
|
|||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.validation.MessageCodesResolver;
|
||||
import org.springframework.validation.Validator;
|
||||
import org.springframework.web.ErrorResponse;
|
||||
import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder;
|
||||
import org.springframework.web.reactive.result.method.annotation.ArgumentResolverConfigurer;
|
||||
import org.springframework.web.reactive.socket.server.WebSocketService;
|
||||
|
@ -99,6 +100,12 @@ public class DelegatingWebFluxConfiguration extends WebFluxConfigurationSupport
|
|||
this.configurers.configureArgumentResolvers(configurer);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureErrorResponseInterceptors(List<ErrorResponse.Interceptor> interceptors) {
|
||||
this.configurers.addErrorResponseInterceptors(interceptors);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||
this.configurers.addResourceHandlers(registry);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2024 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.
|
||||
|
@ -16,6 +16,7 @@
|
|||
|
||||
package org.springframework.web.reactive.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
|
@ -44,6 +45,7 @@ import org.springframework.validation.Errors;
|
|||
import org.springframework.validation.MessageCodesResolver;
|
||||
import org.springframework.validation.Validator;
|
||||
import org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean;
|
||||
import org.springframework.web.ErrorResponse;
|
||||
import org.springframework.web.bind.WebDataBinder;
|
||||
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
|
@ -98,6 +100,9 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware {
|
|||
@Nullable
|
||||
private BlockingExecutionConfigurer blockingExecutionConfigurer;
|
||||
|
||||
@Nullable
|
||||
private List<ErrorResponse.Interceptor> errorResponseInterceptors;
|
||||
|
||||
@Nullable
|
||||
private ViewResolverRegistry viewResolverRegistry;
|
||||
|
||||
|
@ -498,7 +503,7 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware {
|
|||
@Qualifier("webFluxContentTypeResolver") RequestedContentTypeResolver contentTypeResolver) {
|
||||
|
||||
return new ResponseEntityResultHandler(serverCodecConfigurer.getWriters(),
|
||||
contentTypeResolver, reactiveAdapterRegistry);
|
||||
contentTypeResolver, reactiveAdapterRegistry, getErrorResponseInterceptors());
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
@ -508,7 +513,7 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware {
|
|||
@Qualifier("webFluxContentTypeResolver") RequestedContentTypeResolver contentTypeResolver) {
|
||||
|
||||
return new ResponseBodyResultHandler(serverCodecConfigurer.getWriters(),
|
||||
contentTypeResolver, reactiveAdapterRegistry);
|
||||
contentTypeResolver, reactiveAdapterRegistry, getErrorResponseInterceptors());
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
@ -534,6 +539,29 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware {
|
|||
return handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide access to the list of {@link ErrorResponse.Interceptor}'s to apply
|
||||
* in result handlers when rendering error responses.
|
||||
* <p>This method cannot be overridden; use {@link #configureErrorResponseInterceptors(List)} instead.
|
||||
* @since 6.2
|
||||
*/
|
||||
protected final List<ErrorResponse.Interceptor> getErrorResponseInterceptors() {
|
||||
if (this.errorResponseInterceptors == null) {
|
||||
this.errorResponseInterceptors = new ArrayList<>();
|
||||
configureErrorResponseInterceptors(this.errorResponseInterceptors);
|
||||
}
|
||||
return this.errorResponseInterceptors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this method for control over the {@link ErrorResponse.Interceptor}'s
|
||||
* to apply in result handling when rendering error responses.
|
||||
* @param interceptors the list to add handlers to
|
||||
* @since 6.2
|
||||
*/
|
||||
protected void configureErrorResponseInterceptors(List<ErrorResponse.Interceptor> interceptors) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for building the {@link ViewResolverRegistry}. This method is final,
|
||||
* use {@link #configureViewResolvers} to customize view resolvers.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2024 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.
|
||||
|
@ -16,6 +16,8 @@
|
|||
|
||||
package org.springframework.web.reactive.config;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.format.Formatter;
|
||||
import org.springframework.format.FormatterRegistry;
|
||||
|
@ -23,6 +25,7 @@ import org.springframework.http.codec.ServerCodecConfigurer;
|
|||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.validation.MessageCodesResolver;
|
||||
import org.springframework.validation.Validator;
|
||||
import org.springframework.web.ErrorResponse;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder;
|
||||
import org.springframework.web.reactive.result.method.annotation.ArgumentResolverConfigurer;
|
||||
|
@ -133,6 +136,16 @@ public interface WebFluxConfigurer {
|
|||
default void configureArgumentResolvers(ArgumentResolverConfigurer configurer) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add to the list of {@link ErrorResponse.Interceptor}'s to invoke when
|
||||
* rendering an RFC 7807 {@link org.springframework.http.ProblemDetail}
|
||||
* error response.
|
||||
* @param interceptors the handlers to use
|
||||
* @since 6.2
|
||||
*/
|
||||
default void addErrorResponseInterceptors(List<ErrorResponse.Interceptor> interceptors) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure view resolution for rendering responses with a view and a model,
|
||||
* where the view is typically an HTML template but could also be based on
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2024 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.
|
||||
|
@ -27,6 +27,7 @@ import org.springframework.lang.Nullable;
|
|||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.validation.MessageCodesResolver;
|
||||
import org.springframework.validation.Validator;
|
||||
import org.springframework.web.ErrorResponse;
|
||||
import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder;
|
||||
import org.springframework.web.reactive.result.method.annotation.ArgumentResolverConfigurer;
|
||||
import org.springframework.web.reactive.socket.server.WebSocketService;
|
||||
|
@ -95,6 +96,13 @@ public class WebFluxConfigurerComposite implements WebFluxConfigurer {
|
|||
this.delegates.forEach(delegate -> delegate.configureArgumentResolvers(configurer));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addErrorResponseInterceptors(List<ErrorResponse.Interceptor> interceptors) {
|
||||
for (WebFluxConfigurer delegate : this.delegates) {
|
||||
delegate.addErrorResponseInterceptors(interceptors);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureViewResolvers(ViewResolverRegistry registry) {
|
||||
this.delegates.forEach(delegate -> delegate.configureViewResolvers(registry));
|
||||
|
|
|
@ -18,6 +18,7 @@ package org.springframework.web.reactive.result.method.annotation;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -40,6 +41,7 @@ import org.springframework.lang.Nullable;
|
|||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.ErrorResponse;
|
||||
import org.springframework.web.reactive.HandlerMapping;
|
||||
import org.springframework.web.reactive.accept.RequestedContentTypeResolver;
|
||||
import org.springframework.web.reactive.result.HandlerResultHandlerSupport;
|
||||
|
@ -60,6 +62,8 @@ public abstract class AbstractMessageWriterResultHandler extends HandlerResultHa
|
|||
|
||||
private final List<HttpMessageWriter<?>> messageWriters;
|
||||
|
||||
private final List<ErrorResponse.Interceptor> errorResponseInterceptors = new ArrayList<>();
|
||||
|
||||
private final List<MediaType> problemMediaTypes =
|
||||
Arrays.asList(MediaType.APPLICATION_PROBLEM_JSON, MediaType.APPLICATION_PROBLEM_XML);
|
||||
|
||||
|
@ -86,9 +90,24 @@ public abstract class AbstractMessageWriterResultHandler extends HandlerResultHa
|
|||
protected AbstractMessageWriterResultHandler(List<HttpMessageWriter<?>> messageWriters,
|
||||
RequestedContentTypeResolver contentTypeResolver, ReactiveAdapterRegistry adapterRegistry) {
|
||||
|
||||
this(messageWriters, contentTypeResolver, adapterRegistry, Collections.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Variant of
|
||||
* {@link #AbstractMessageWriterResultHandler(List, RequestedContentTypeResolver, ReactiveAdapterRegistry)}
|
||||
* with additional list of {@link ErrorResponse.Interceptor}s for return
|
||||
* value handling.
|
||||
* @since 6.2
|
||||
*/
|
||||
protected AbstractMessageWriterResultHandler(List<HttpMessageWriter<?>> messageWriters,
|
||||
RequestedContentTypeResolver contentTypeResolver, ReactiveAdapterRegistry adapterRegistry,
|
||||
List<ErrorResponse.Interceptor> interceptors) {
|
||||
|
||||
super(contentTypeResolver, adapterRegistry);
|
||||
Assert.notEmpty(messageWriters, "At least one message writer is required");
|
||||
this.messageWriters = messageWriters;
|
||||
this.errorResponseInterceptors.addAll(interceptors);
|
||||
}
|
||||
|
||||
|
||||
|
@ -99,6 +118,29 @@ public abstract class AbstractMessageWriterResultHandler extends HandlerResultHa
|
|||
return this.messageWriters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the configured {@link ErrorResponse.Interceptor}'s.
|
||||
* @since 6.2
|
||||
*/
|
||||
public List<ErrorResponse.Interceptor> getErrorResponseInterceptors() {
|
||||
return this.errorResponseInterceptors;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Invoke the configured {@link ErrorResponse.Interceptor}'s.
|
||||
* @since 6.2
|
||||
*/
|
||||
protected void invokeErrorResponseInterceptors(ProblemDetail detail, @Nullable ErrorResponse errorResponse) {
|
||||
try {
|
||||
for (ErrorResponse.Interceptor handler : this.errorResponseInterceptors) {
|
||||
handler.handleError(detail, errorResponse);
|
||||
}
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a given body to the response with {@link HttpMessageWriter}.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2024 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.
|
||||
|
@ -17,6 +17,7 @@
|
|||
package org.springframework.web.reactive.result.method.annotation;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
@ -27,6 +28,7 @@ import org.springframework.core.annotation.AnnotatedElementUtils;
|
|||
import org.springframework.http.HttpStatusCode;
|
||||
import org.springframework.http.ProblemDetail;
|
||||
import org.springframework.http.codec.HttpMessageWriter;
|
||||
import org.springframework.web.ErrorResponse;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.reactive.HandlerResult;
|
||||
import org.springframework.web.reactive.HandlerResultHandler;
|
||||
|
@ -69,7 +71,21 @@ public class ResponseBodyResultHandler extends AbstractMessageWriterResultHandle
|
|||
public ResponseBodyResultHandler(List<HttpMessageWriter<?>> writers,
|
||||
RequestedContentTypeResolver resolver, ReactiveAdapterRegistry registry) {
|
||||
|
||||
super(writers, resolver, registry);
|
||||
this(writers, resolver, registry, Collections.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Variant of
|
||||
* {@link #ResponseBodyResultHandler(List, RequestedContentTypeResolver, ReactiveAdapterRegistry)}
|
||||
* with additional list of {@link ErrorResponse.Interceptor}s for return
|
||||
* value handling.
|
||||
* @since 6.2
|
||||
*/
|
||||
public ResponseBodyResultHandler(List<HttpMessageWriter<?>> writers,
|
||||
RequestedContentTypeResolver resolver, ReactiveAdapterRegistry registry,
|
||||
List<ErrorResponse.Interceptor> interceptors) {
|
||||
|
||||
super(writers, resolver, registry, interceptors);
|
||||
setOrder(100);
|
||||
}
|
||||
|
||||
|
@ -92,6 +108,7 @@ public class ResponseBodyResultHandler extends AbstractMessageWriterResultHandle
|
|||
URI path = URI.create(exchange.getRequest().getPath().value());
|
||||
detail.setInstance(path);
|
||||
}
|
||||
invokeErrorResponseInterceptors(detail, null);
|
||||
}
|
||||
return writeBody(body, bodyTypeParameter, exchange);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2024 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.
|
||||
|
@ -18,6 +18,7 @@ package org.springframework.web.reactive.result.method.annotation;
|
|||
|
||||
import java.net.URI;
|
||||
import java.time.Instant;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -78,7 +79,20 @@ public class ResponseEntityResultHandler extends AbstractMessageWriterResultHand
|
|||
public ResponseEntityResultHandler(List<HttpMessageWriter<?>> writers,
|
||||
RequestedContentTypeResolver resolver, ReactiveAdapterRegistry registry) {
|
||||
|
||||
super(writers, resolver, registry);
|
||||
this(writers, resolver, registry, Collections.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor with an {@link ReactiveAdapterRegistry} instance.
|
||||
* @param writers the writers for serializing to the response body
|
||||
* @param resolver to determine the requested content type
|
||||
* @param registry for adaptation to reactive types
|
||||
*/
|
||||
public ResponseEntityResultHandler(List<HttpMessageWriter<?>> writers,
|
||||
RequestedContentTypeResolver resolver, ReactiveAdapterRegistry registry,
|
||||
List<ErrorResponse.Interceptor> interceptors) {
|
||||
|
||||
super(writers, resolver, registry, interceptors);
|
||||
setOrder(0);
|
||||
}
|
||||
|
||||
|
@ -166,6 +180,8 @@ public class ResponseEntityResultHandler extends AbstractMessageWriterResultHand
|
|||
" doesn't match the ProblemDetail status: " + detail.getStatus());
|
||||
}
|
||||
}
|
||||
invokeErrorResponseInterceptors(
|
||||
detail, (returnValue instanceof ErrorResponse response ? response : null));
|
||||
}
|
||||
|
||||
if (httpEntity instanceof ResponseEntity<?> responseEntity) {
|
||||
|
|
|
@ -35,8 +35,10 @@ import org.springframework.http.codec.HttpMessageWriter;
|
|||
import org.springframework.http.codec.ServerCodecConfigurer;
|
||||
import org.springframework.validation.Validator;
|
||||
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
||||
import org.springframework.web.ErrorResponse;
|
||||
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
|
||||
import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder;
|
||||
import org.springframework.web.reactive.result.method.annotation.ResponseBodyResultHandler;
|
||||
import org.springframework.web.reactive.socket.server.WebSocketService;
|
||||
import org.springframework.web.reactive.socket.server.support.WebSocketHandlerAdapter;
|
||||
|
||||
|
@ -153,6 +155,25 @@ public class DelegatingWebFluxConfigurationTests {
|
|||
verify(webFluxConfigurer).configureContentTypeResolver(any(RequestedContentTypeResolverBuilder.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void addErrorResponseInterceptors() {
|
||||
ErrorResponse.Interceptor interceptor = (detail, errorResponse) -> {};
|
||||
WebFluxConfigurer configurer = new WebFluxConfigurer() {
|
||||
@Override
|
||||
public void addErrorResponseInterceptors(List<ErrorResponse.Interceptor> interceptors) {
|
||||
interceptors.add(interceptor);
|
||||
}
|
||||
};
|
||||
delegatingConfig.setConfigurers(Collections.singletonList(configurer));
|
||||
|
||||
ResponseBodyResultHandler resultHandler = delegatingConfig.responseBodyResultHandler(
|
||||
delegatingConfig.webFluxAdapterRegistry(),
|
||||
delegatingConfig.serverCodecConfigurer(),
|
||||
delegatingConfig.webFluxContentTypeResolver());
|
||||
|
||||
assertThat(resultHandler.getErrorResponseInterceptors()).containsExactly(interceptor);
|
||||
}
|
||||
|
||||
@Test
|
||||
void viewResolutionResultHandler() {
|
||||
delegatingConfig.setConfigurers(Collections.singletonList(webFluxConfigurer));
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2024 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,6 +26,7 @@ import org.springframework.lang.Nullable;
|
|||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.validation.MessageCodesResolver;
|
||||
import org.springframework.validation.Validator;
|
||||
import org.springframework.web.ErrorResponse;
|
||||
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
|
||||
import org.springframework.web.servlet.HandlerExceptionResolver;
|
||||
|
@ -133,6 +134,11 @@ public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
|
|||
this.configurers.extendHandlerExceptionResolvers(exceptionResolvers);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureErrorResponseInterceptors(List<ErrorResponse.Interceptor> interceptors) {
|
||||
this.configurers.addErrorResponseInterceptors(interceptors);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected Validator getValidator() {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2024 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.
|
||||
|
@ -67,6 +67,7 @@ import org.springframework.validation.Errors;
|
|||
import org.springframework.validation.MessageCodesResolver;
|
||||
import org.springframework.validation.Validator;
|
||||
import org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean;
|
||||
import org.springframework.web.ErrorResponse;
|
||||
import org.springframework.web.HttpRequestHandler;
|
||||
import org.springframework.web.accept.ContentNegotiationManager;
|
||||
import org.springframework.web.bind.WebDataBinder;
|
||||
|
@ -251,6 +252,9 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
|
|||
@Nullable
|
||||
private List<HttpMessageConverter<?>> messageConverters;
|
||||
|
||||
@Nullable
|
||||
private List<ErrorResponse.Interceptor> errorResponseInterceptors;
|
||||
|
||||
@Nullable
|
||||
private Map<String, CorsConfiguration> corsConfigurations;
|
||||
|
||||
|
@ -653,6 +657,7 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
|
|||
adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer(conversionService, validator));
|
||||
adapter.setCustomArgumentResolvers(getArgumentResolvers());
|
||||
adapter.setCustomReturnValueHandlers(getReturnValueHandlers());
|
||||
adapter.setErrorResponseInterceptors(getErrorResponseInterceptors());
|
||||
|
||||
if (jackson2Present) {
|
||||
adapter.setRequestBodyAdvice(Collections.singletonList(new JsonViewRequestBodyAdvice()));
|
||||
|
@ -1053,6 +1058,7 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
|
|||
exceptionHandlerResolver.setMessageConverters(getMessageConverters());
|
||||
exceptionHandlerResolver.setCustomArgumentResolvers(getArgumentResolvers());
|
||||
exceptionHandlerResolver.setCustomReturnValueHandlers(getReturnValueHandlers());
|
||||
exceptionHandlerResolver.setErrorResponseInterceptors(getErrorResponseInterceptors());
|
||||
if (jackson2Present) {
|
||||
exceptionHandlerResolver.setResponseBodyAdvice(
|
||||
Collections.singletonList(new JsonViewResponseBodyAdvice()));
|
||||
|
@ -1079,6 +1085,29 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
|
|||
return new ExceptionHandlerExceptionResolver();
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide access to the list of {@link ErrorResponse.Interceptor}'s to apply
|
||||
* when rendering error responses.
|
||||
* <p>This method cannot be overridden; use {@link #configureErrorResponseInterceptors(List)} instead.
|
||||
* @since 6.2
|
||||
*/
|
||||
protected final List<ErrorResponse.Interceptor> getErrorResponseInterceptors() {
|
||||
if (this.errorResponseInterceptors == null) {
|
||||
this.errorResponseInterceptors = new ArrayList<>();
|
||||
configureErrorResponseInterceptors(this.errorResponseInterceptors);
|
||||
}
|
||||
return this.errorResponseInterceptors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this method for control over the {@link ErrorResponse.Interceptor}'s
|
||||
* to apply when rendering error responses.
|
||||
* @param interceptors the list to add handlers to
|
||||
* @since 6.2
|
||||
*/
|
||||
protected void configureErrorResponseInterceptors(List<ErrorResponse.Interceptor> interceptors) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a {@link ViewResolverComposite} that contains a chain of view resolvers
|
||||
* to use for view resolution.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2024 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.
|
||||
|
@ -25,6 +25,7 @@ import org.springframework.http.converter.HttpMessageConverter;
|
|||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.validation.MessageCodesResolver;
|
||||
import org.springframework.validation.Validator;
|
||||
import org.springframework.web.ErrorResponse;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
|
||||
|
@ -221,6 +222,16 @@ public interface WebMvcConfigurer {
|
|||
default void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add to the list of {@link ErrorResponse.Interceptor}'s to apply when
|
||||
* rendering an RFC 7807 {@link org.springframework.http.ProblemDetail}
|
||||
* error response.
|
||||
* @param interceptors the interceptors to use
|
||||
* @since 6.2
|
||||
*/
|
||||
default void addErrorResponseInterceptors(List<ErrorResponse.Interceptor> interceptors) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a custom {@link Validator} instead of the one created by default.
|
||||
* The default implementation, assuming JSR-303 is on the classpath, is:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2024 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.
|
||||
|
@ -25,6 +25,7 @@ import org.springframework.lang.Nullable;
|
|||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.validation.MessageCodesResolver;
|
||||
import org.springframework.validation.Validator;
|
||||
import org.springframework.web.ErrorResponse;
|
||||
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
|
||||
import org.springframework.web.servlet.HandlerExceptionResolver;
|
||||
|
@ -159,6 +160,13 @@ class WebMvcConfigurerComposite implements WebMvcConfigurer {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addErrorResponseInterceptors(List<ErrorResponse.Interceptor> interceptors) {
|
||||
for (WebMvcConfigurer delegate : this.delegates) {
|
||||
delegate.addErrorResponseInterceptors(interceptors);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Validator getValidator() {
|
||||
Validator selected = null;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2024 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.
|
||||
|
@ -57,6 +57,7 @@ import org.springframework.util.Assert;
|
|||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.MimeTypeUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.ErrorResponse;
|
||||
import org.springframework.web.HttpMediaTypeNotAcceptableException;
|
||||
import org.springframework.web.accept.ContentNegotiationManager;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
|
@ -99,6 +100,8 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
|
|||
private final List<MediaType> problemMediaTypes =
|
||||
Arrays.asList(MediaType.APPLICATION_PROBLEM_JSON, MediaType.APPLICATION_PROBLEM_XML);
|
||||
|
||||
private final List<ErrorResponse.Interceptor> errorResponseInterceptors = new ArrayList<>();
|
||||
|
||||
private final Set<String> safeExtensions = new HashSet<>();
|
||||
|
||||
|
||||
|
@ -119,17 +122,32 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
|
|||
}
|
||||
|
||||
/**
|
||||
* Constructor with list of converters and ContentNegotiationManager as well
|
||||
* as request/response body advice instances.
|
||||
* Variant of {@link #AbstractMessageConverterMethodProcessor(List)}
|
||||
* with an additional {@link ContentNegotiationManager} for return
|
||||
* value handling.
|
||||
*/
|
||||
protected AbstractMessageConverterMethodProcessor(List<HttpMessageConverter<?>> converters,
|
||||
@Nullable ContentNegotiationManager manager, @Nullable List<Object> requestResponseBodyAdvice) {
|
||||
|
||||
this(converters, manager, requestResponseBodyAdvice, Collections.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Variant of {@link #AbstractMessageConverterMethodProcessor(List, ContentNegotiationManager, List)}
|
||||
* with additional list of {@link ErrorResponse.Interceptor}s for return
|
||||
* value handling.
|
||||
* @since 6.2
|
||||
*/
|
||||
protected AbstractMessageConverterMethodProcessor(List<HttpMessageConverter<?>> converters,
|
||||
@Nullable ContentNegotiationManager manager, @Nullable List<Object> requestResponseBodyAdvice,
|
||||
List<ErrorResponse.Interceptor> interceptors) {
|
||||
|
||||
super(converters, requestResponseBodyAdvice);
|
||||
|
||||
this.contentNegotiationManager = (manager != null ? manager : new ContentNegotiationManager());
|
||||
this.safeExtensions.addAll(this.contentNegotiationManager.getAllFileExtensions());
|
||||
this.safeExtensions.addAll(SAFE_EXTENSIONS);
|
||||
this.errorResponseInterceptors.addAll(interceptors);
|
||||
}
|
||||
|
||||
|
||||
|
@ -144,6 +162,21 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
|
|||
return new ServletServerHttpResponse(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke the configured {@link ErrorResponse.Interceptor}'s.
|
||||
* @since 6.2
|
||||
*/
|
||||
protected void invokeErrorResponseInterceptors(ProblemDetail detail, @Nullable ErrorResponse errorResponse) {
|
||||
try {
|
||||
for (ErrorResponse.Interceptor handler : this.errorResponseInterceptors) {
|
||||
handler.handleError(detail, errorResponse);
|
||||
}
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the given return value to the given web request. Delegates to
|
||||
* {@link #writeWithMessageConverters(Object, MethodParameter, ServletServerHttpRequest, ServletServerHttpResponse)}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2024 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.
|
||||
|
@ -39,6 +39,7 @@ import org.springframework.http.converter.StringHttpMessageConverter;
|
|||
import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.web.ErrorResponse;
|
||||
import org.springframework.web.accept.ContentNegotiationManager;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.context.request.ServletWebRequest;
|
||||
|
@ -106,6 +107,8 @@ public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExce
|
|||
|
||||
private final List<Object> responseBodyAdvice = new ArrayList<>();
|
||||
|
||||
private final List<ErrorResponse.Interceptor> errorResponseInterceptors = new ArrayList<>();
|
||||
|
||||
@Nullable
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
|
@ -239,6 +242,27 @@ public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExce
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure a list of {@link ErrorResponse.Interceptor}'s to apply when
|
||||
* rendering an RFC 7807 {@link org.springframework.http.ProblemDetail}
|
||||
* error response.
|
||||
* @param interceptors the handlers to use
|
||||
* @since 6.2
|
||||
*/
|
||||
public void setErrorResponseInterceptors(List<ErrorResponse.Interceptor> interceptors) {
|
||||
this.errorResponseInterceptors.clear();
|
||||
this.errorResponseInterceptors.addAll(interceptors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link #setErrorResponseInterceptors(List) configured}
|
||||
* {@link ErrorResponse.Interceptor}'s.
|
||||
* @since 6.2
|
||||
*/
|
||||
public List<ErrorResponse.Interceptor> getErrorResponseInterceptors() {
|
||||
return this.errorResponseInterceptors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(@Nullable ApplicationContext applicationContext) {
|
||||
this.applicationContext = applicationContext;
|
||||
|
@ -358,12 +382,14 @@ public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExce
|
|||
handlers.add(new ModelMethodProcessor());
|
||||
handlers.add(new ViewMethodReturnValueHandler());
|
||||
handlers.add(new HttpEntityMethodProcessor(
|
||||
getMessageConverters(), this.contentNegotiationManager, this.responseBodyAdvice));
|
||||
getMessageConverters(), this.contentNegotiationManager, this.responseBodyAdvice,
|
||||
this.errorResponseInterceptors));
|
||||
|
||||
// Annotation-based return value types
|
||||
handlers.add(new ServletModelAttributeMethodProcessor(false));
|
||||
handlers.add(new RequestResponseBodyMethodProcessor(
|
||||
getMessageConverters(), this.contentNegotiationManager, this.responseBodyAdvice));
|
||||
getMessageConverters(), this.contentNegotiationManager, this.responseBodyAdvice,
|
||||
this.errorResponseInterceptors));
|
||||
|
||||
// Multi-purpose return value types
|
||||
handlers.add(new ViewNameMethodReturnValueHandler());
|
||||
|
|
|
@ -103,8 +103,9 @@ public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodPro
|
|||
}
|
||||
|
||||
/**
|
||||
* Complete constructor for resolving {@code HttpEntity} and handling
|
||||
* {@code ResponseEntity}.
|
||||
* Variant of {@link #HttpEntityMethodProcessor(List, List)}
|
||||
* with an additional {@link ContentNegotiationManager} argument for return
|
||||
* value handling.
|
||||
*/
|
||||
public HttpEntityMethodProcessor(List<HttpMessageConverter<?>> converters,
|
||||
@Nullable ContentNegotiationManager manager, List<Object> requestResponseBodyAdvice) {
|
||||
|
@ -112,6 +113,19 @@ public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodPro
|
|||
super(converters, manager, requestResponseBodyAdvice);
|
||||
}
|
||||
|
||||
/**
|
||||
* Variant of {@link #HttpEntityMethodProcessor(List, ContentNegotiationManager, List)}
|
||||
* with additional list of {@link ErrorResponse.Interceptor}s for return
|
||||
* value handling.
|
||||
* @since 6.2
|
||||
*/
|
||||
public HttpEntityMethodProcessor(List<HttpMessageConverter<?>> converters,
|
||||
@Nullable ContentNegotiationManager manager, List<Object> requestResponseBodyAdvice,
|
||||
List<ErrorResponse.Interceptor> interceptors) {
|
||||
|
||||
super(converters, manager, requestResponseBodyAdvice, interceptors);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean supportsParameter(MethodParameter parameter) {
|
||||
|
@ -204,6 +218,8 @@ public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodPro
|
|||
" doesn't match the ProblemDetail status: " + detail.getStatus());
|
||||
}
|
||||
}
|
||||
invokeErrorResponseInterceptors(
|
||||
detail, (returnValue instanceof ErrorResponse response ? response : null));
|
||||
}
|
||||
|
||||
HttpHeaders outputHeaders = outputMessage.getHeaders();
|
||||
|
|
|
@ -55,6 +55,7 @@ import org.springframework.util.ClassUtils;
|
|||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.ReflectionUtils.MethodFilter;
|
||||
import org.springframework.validation.method.MethodValidator;
|
||||
import org.springframework.web.ErrorResponse;
|
||||
import org.springframework.web.accept.ContentNegotiationManager;
|
||||
import org.springframework.web.bind.annotation.InitBinder;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
|
@ -166,6 +167,8 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
|
|||
@Nullable
|
||||
private WebBindingInitializer webBindingInitializer;
|
||||
|
||||
private final List<ErrorResponse.Interceptor> errorResponseInterceptors = new ArrayList<>();
|
||||
|
||||
@Nullable
|
||||
private MethodValidator methodValidator;
|
||||
|
||||
|
@ -395,6 +398,27 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
|
|||
return this.webBindingInitializer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure a list of {@link ErrorResponse.Interceptor}'s to apply when
|
||||
* rendering an RFC 7807 {@link org.springframework.http.ProblemDetail}
|
||||
* error response.
|
||||
* @param interceptors the interceptors to use
|
||||
* @since 6.2
|
||||
*/
|
||||
public void setErrorResponseInterceptors(List<ErrorResponse.Interceptor> interceptors) {
|
||||
this.errorResponseInterceptors.clear();
|
||||
this.errorResponseInterceptors.addAll(interceptors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link #setErrorResponseInterceptors(List) configured}
|
||||
* {@link ErrorResponse.Interceptor}'s.
|
||||
* @since 6.2
|
||||
*/
|
||||
public List<ErrorResponse.Interceptor> getErrorResponseInterceptors() {
|
||||
return this.errorResponseInterceptors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default {@link AsyncTaskExecutor} to use when a controller method
|
||||
* return a {@link Callable}. Controller methods can override this default on
|
||||
|
@ -746,7 +770,7 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
|
|||
this.reactiveAdapterRegistry, this.taskExecutor, this.contentNegotiationManager));
|
||||
handlers.add(new StreamingResponseBodyReturnValueHandler());
|
||||
handlers.add(new HttpEntityMethodProcessor(getMessageConverters(),
|
||||
this.contentNegotiationManager, this.requestResponseBodyAdvice));
|
||||
this.contentNegotiationManager, this.requestResponseBodyAdvice, this.errorResponseInterceptors));
|
||||
handlers.add(new HttpHeadersReturnValueHandler());
|
||||
handlers.add(new CallableMethodReturnValueHandler());
|
||||
handlers.add(new DeferredResultMethodReturnValueHandler());
|
||||
|
@ -755,7 +779,7 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
|
|||
// Annotation-based return value types
|
||||
handlers.add(new ServletModelAttributeMethodProcessor(false));
|
||||
handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),
|
||||
this.contentNegotiationManager, this.requestResponseBodyAdvice));
|
||||
this.contentNegotiationManager, this.requestResponseBodyAdvice, this.errorResponseInterceptors));
|
||||
|
||||
// Multi-purpose return value types
|
||||
handlers.add(new ViewNameMethodReturnValueHandler());
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2024 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.http.server.ServletServerHttpRequest;
|
|||
import org.springframework.http.server.ServletServerHttpResponse;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.ErrorResponse;
|
||||
import org.springframework.web.HttpMediaTypeNotAcceptableException;
|
||||
import org.springframework.web.HttpMediaTypeNotSupportedException;
|
||||
import org.springframework.web.accept.ContentNegotiationManager;
|
||||
|
@ -99,8 +100,9 @@ public class RequestResponseBodyMethodProcessor extends AbstractMessageConverter
|
|||
}
|
||||
|
||||
/**
|
||||
* Complete constructor for resolving {@code @RequestBody} and handling
|
||||
* {@code @ResponseBody}.
|
||||
* Variant of {@link #RequestResponseBodyMethodProcessor(List, List)}
|
||||
* with an additional {@link ContentNegotiationManager} argument, for return
|
||||
* value handling.
|
||||
*/
|
||||
public RequestResponseBodyMethodProcessor(List<HttpMessageConverter<?>> converters,
|
||||
@Nullable ContentNegotiationManager manager, @Nullable List<Object> requestResponseBodyAdvice) {
|
||||
|
@ -108,6 +110,19 @@ public class RequestResponseBodyMethodProcessor extends AbstractMessageConverter
|
|||
super(converters, manager, requestResponseBodyAdvice);
|
||||
}
|
||||
|
||||
/**
|
||||
* Variant of{@link #RequestResponseBodyMethodProcessor(List, ContentNegotiationManager, List)}
|
||||
* with an additional {@link ErrorResponse.Interceptor} argument for return
|
||||
* value handling.
|
||||
* @since 6.2
|
||||
*/
|
||||
public RequestResponseBodyMethodProcessor(List<HttpMessageConverter<?>> converters,
|
||||
@Nullable ContentNegotiationManager manager, List<Object> requestResponseBodyAdvice,
|
||||
List<ErrorResponse.Interceptor> interceptors) {
|
||||
|
||||
super(converters, manager, requestResponseBodyAdvice, interceptors);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean supportsParameter(MethodParameter parameter) {
|
||||
|
@ -184,6 +199,7 @@ public class RequestResponseBodyMethodProcessor extends AbstractMessageConverter
|
|||
URI path = URI.create(inputMessage.getServletRequest().getRequestURI());
|
||||
detail.setInstance(path);
|
||||
}
|
||||
invokeErrorResponseInterceptors(detail, null);
|
||||
}
|
||||
|
||||
// Try even with null return value. ResponseBodyAdvice could get involved.
|
||||
|
|
|
@ -33,6 +33,7 @@ import org.springframework.http.converter.StringHttpMessageConverter;
|
|||
import org.springframework.util.PathMatcher;
|
||||
import org.springframework.validation.DefaultMessageCodesResolver;
|
||||
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
||||
import org.springframework.web.ErrorResponse;
|
||||
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
|
||||
import org.springframework.web.context.support.GenericWebApplicationContext;
|
||||
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||
|
@ -198,8 +199,35 @@ public class DelegatingWebMvcConfigurationTests {
|
|||
(HandlerExceptionResolverComposite) webMvcConfig
|
||||
.handlerExceptionResolver(webMvcConfig.mvcContentNegotiationManager());
|
||||
|
||||
assertThat(composite.getExceptionResolvers())
|
||||
.as("Only one custom converter is expected").hasSize(1);
|
||||
assertThat(composite.getExceptionResolvers()).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addErrorResponseInterceptors() {
|
||||
ErrorResponse.Interceptor interceptor = (detail, errorResponse) -> {};
|
||||
WebMvcConfigurer configurer = new WebMvcConfigurer() {
|
||||
@Override
|
||||
public void addErrorResponseInterceptors(List<ErrorResponse.Interceptor> interceptors) {
|
||||
interceptors.add(interceptor);
|
||||
}
|
||||
};
|
||||
webMvcConfig.setConfigurers(Collections.singletonList(configurer));
|
||||
|
||||
RequestMappingHandlerAdapter adapter = webMvcConfig.requestMappingHandlerAdapter(
|
||||
webMvcConfig.mvcContentNegotiationManager(),
|
||||
webMvcConfig.mvcConversionService(),
|
||||
webMvcConfig.getValidator());
|
||||
|
||||
assertThat(adapter.getErrorResponseInterceptors()).containsExactly(interceptor);
|
||||
|
||||
HandlerExceptionResolverComposite composite =
|
||||
(HandlerExceptionResolverComposite) webMvcConfig.handlerExceptionResolver(
|
||||
webMvcConfig.mvcContentNegotiationManager());
|
||||
|
||||
ExceptionHandlerExceptionResolver resolver =
|
||||
(ExceptionHandlerExceptionResolver) composite.getExceptionResolvers().get(0);
|
||||
|
||||
assertThat(resolver.getErrorResponseInterceptors()).containsExactly(interceptor);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
Loading…
Reference in New Issue