Merge pull request #36288 from mzeijen

* pr/36288:
  Polish "Order auto-configured ProblemDetailsExceptionHandler beans"
  Order auto-configured ProblemDetailsExceptionHandler beans

Closes gh-36288
This commit is contained in:
Stephane Nicoll
2023-08-02 15:28:43 +02:00
4 changed files with 71 additions and 0 deletions

View File

@@ -357,6 +357,7 @@ public class WebFluxAutoConfiguration {
@Bean
@ConditionalOnMissingBean(ResponseEntityExceptionHandler.class)
@Order(0)
ProblemDetailsExceptionHandler problemDetailsExceptionHandler() {
return new ProblemDetailsExceptionHandler();
}

View File

@@ -662,6 +662,7 @@ public class WebMvcAutoConfiguration {
@Bean
@ConditionalOnMissingBean(ResponseEntityExceptionHandler.class)
@Order(0)
ProblemDetailsExceptionHandler problemDetailsExceptionHandler() {
return new ProblemDetailsExceptionHandler();
}

View File

@@ -37,6 +37,7 @@ import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.assertj.core.api.Assertions;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
@@ -49,6 +50,8 @@ import org.springframework.boot.autoconfigure.validation.ValidationAutoConfigura
import org.springframework.boot.autoconfigure.validation.ValidatorAdapter;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration.WebFluxConfig;
import org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfigurationTests.OrderedControllerAdviceBeansConfiguration.HighestOrderedControllerAdvice;
import org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfigurationTests.OrderedControllerAdviceBeansConfiguration.LowestOrderedControllerAdvice;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.test.context.runner.ContextConsumer;
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
@@ -80,6 +83,7 @@ import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.filter.reactive.HiddenHttpMethodFilter;
import org.springframework.web.method.ControllerAdviceBean;
import org.springframework.web.reactive.HandlerMapping;
import org.springframework.web.reactive.accept.RequestedContentTypeResolver;
import org.springframework.web.reactive.config.BlockingExecutionConfigurer;
@@ -671,6 +675,17 @@ class WebFluxAutoConfigurationTests {
.hasSingleBean(CustomExceptionHandler.class));
}
@Test
void problemDetailsExceptionHandlerIsOrderedAt0() {
this.contextRunner.withPropertyValues("spring.webflux.problemdetails.enabled:true")
.withUserConfiguration(OrderedControllerAdviceBeansConfiguration.class)
.run((context) -> assertThat(
ControllerAdviceBean.findAnnotatedBeans(context).stream().map(ControllerAdviceBean::getBeanType))
.asInstanceOf(InstanceOfAssertFactories.list(Class.class))
.containsExactly(HighestOrderedControllerAdvice.class, ProblemDetailsExceptionHandler.class,
LowestOrderedControllerAdvice.class));
}
@Test
void asyncTaskExecutorWithApplicationTaskExecutor() {
this.contextRunner.withConfiguration(AutoConfigurations.of(TaskExecutionAutoConfiguration.class))
@@ -1016,6 +1031,25 @@ class WebFluxAutoConfigurationTests {
}
@Configuration(proxyBeanMethods = false)
@Import({ OrderedControllerAdviceBeansConfiguration.LowestOrderedControllerAdvice.class,
OrderedControllerAdviceBeansConfiguration.HighestOrderedControllerAdvice.class })
static class OrderedControllerAdviceBeansConfiguration {
@ControllerAdvice
@Order
static class LowestOrderedControllerAdvice {
}
@ControllerAdvice
@Order(Ordered.HIGHEST_PRECEDENCE)
static class HighestOrderedControllerAdvice {
}
}
@Aspect
static class ExceptionHandlerInterceptor {

View File

@@ -39,6 +39,7 @@ import jakarta.validation.ValidatorFactory;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.junit.jupiter.api.Test;
import org.springframework.aop.support.AopUtils;
@@ -51,6 +52,8 @@ import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguratio
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration;
import org.springframework.boot.autoconfigure.validation.ValidatorAdapter;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfigurationTests.OrderedControllerAdviceBeansConfiguration.HighestOrderedControllerAdvice;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfigurationTests.OrderedControllerAdviceBeansConfiguration.LowestOrderedControllerAdvice;
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
import org.springframework.boot.test.context.runner.ContextConsumer;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
@@ -65,6 +68,8 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
@@ -89,6 +94,7 @@ import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.FormContentFilter;
import org.springframework.web.filter.HiddenHttpMethodFilter;
import org.springframework.web.filter.RequestContextFilter;
import org.springframework.web.method.ControllerAdviceBean;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.FlashMap;
import org.springframework.web.servlet.FlashMapManager;
@@ -972,6 +978,17 @@ class WebMvcAutoConfigurationTests {
.hasSingleBean(CustomExceptionHandler.class));
}
@Test
void problemDetailsExceptionHandlerIsOrderedAt0() {
this.contextRunner.withPropertyValues("spring.mvc.problemdetails.enabled:true")
.withUserConfiguration(OrderedControllerAdviceBeansConfiguration.class)
.run((context) -> assertThat(
ControllerAdviceBean.findAnnotatedBeans(context).stream().map(ControllerAdviceBean::getBeanType))
.asInstanceOf(InstanceOfAssertFactories.list(Class.class))
.containsExactly(HighestOrderedControllerAdvice.class, ProblemDetailsExceptionHandler.class,
OrderedControllerAdviceBeansConfiguration.LowestOrderedControllerAdvice.class));
}
private void assertResourceHttpRequestHandler(AssertableWebApplicationContext context,
Consumer<ResourceHttpRequestHandler> handlerConsumer) {
Map<String, Object> handlerMap = getHandlerMap(context.getBean("resourceHandlerMapping", HandlerMapping.class));
@@ -1496,6 +1513,24 @@ class WebMvcAutoConfigurationTests {
}
@Configuration(proxyBeanMethods = false)
@Import({ LowestOrderedControllerAdvice.class, HighestOrderedControllerAdvice.class })
static class OrderedControllerAdviceBeansConfiguration {
@ControllerAdvice
@Order
static class LowestOrderedControllerAdvice {
}
@ControllerAdvice
@Order(Ordered.HIGHEST_PRECEDENCE)
static class HighestOrderedControllerAdvice {
}
}
@ControllerAdvice
static class CustomExceptionHandler extends ResponseEntityExceptionHandler {