|
|
|
@ -1,5 +1,5 @@ |
|
|
|
/* |
|
|
|
/* |
|
|
|
* Copyright 2002-2022 the original author or authors. |
|
|
|
* Copyright 2002-2023 the original author or authors. |
|
|
|
* |
|
|
|
* |
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
|
|
* you may not use this file except in compliance with the License. |
|
|
|
* you may not use this file except in compliance with the License. |
|
|
|
@ -19,6 +19,7 @@ package org.springframework.web.reactive; |
|
|
|
import java.time.Duration; |
|
|
|
import java.time.Duration; |
|
|
|
import java.util.Collections; |
|
|
|
import java.util.Collections; |
|
|
|
import java.util.List; |
|
|
|
import java.util.List; |
|
|
|
|
|
|
|
import java.util.Map; |
|
|
|
import java.util.concurrent.atomic.AtomicReference; |
|
|
|
import java.util.concurrent.atomic.AtomicReference; |
|
|
|
|
|
|
|
|
|
|
|
import org.junit.jupiter.api.BeforeEach; |
|
|
|
import org.junit.jupiter.api.BeforeEach; |
|
|
|
@ -32,15 +33,23 @@ import org.springframework.context.annotation.Bean; |
|
|
|
import org.springframework.context.annotation.Configuration; |
|
|
|
import org.springframework.context.annotation.Configuration; |
|
|
|
import org.springframework.core.codec.CharSequenceEncoder; |
|
|
|
import org.springframework.core.codec.CharSequenceEncoder; |
|
|
|
import org.springframework.http.HttpStatus; |
|
|
|
import org.springframework.http.HttpStatus; |
|
|
|
|
|
|
|
import org.springframework.http.MediaType; |
|
|
|
import org.springframework.http.codec.EncoderHttpMessageWriter; |
|
|
|
import org.springframework.http.codec.EncoderHttpMessageWriter; |
|
|
|
|
|
|
|
import org.springframework.http.codec.ServerCodecConfigurer; |
|
|
|
import org.springframework.stereotype.Controller; |
|
|
|
import org.springframework.stereotype.Controller; |
|
|
|
|
|
|
|
import org.springframework.web.bind.annotation.ControllerAdvice; |
|
|
|
import org.springframework.web.bind.annotation.RequestBody; |
|
|
|
import org.springframework.web.bind.annotation.RequestBody; |
|
|
|
import org.springframework.web.bind.annotation.RequestMapping; |
|
|
|
import org.springframework.web.bind.annotation.RequestMapping; |
|
|
|
import org.springframework.web.bind.annotation.ResponseBody; |
|
|
|
import org.springframework.web.bind.annotation.ResponseBody; |
|
|
|
import org.springframework.web.reactive.accept.HeaderContentTypeResolver; |
|
|
|
import org.springframework.web.reactive.accept.HeaderContentTypeResolver; |
|
|
|
|
|
|
|
import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping; |
|
|
|
|
|
|
|
import org.springframework.web.reactive.resource.ResourceWebHandler; |
|
|
|
|
|
|
|
import org.springframework.web.reactive.result.SimpleHandlerAdapter; |
|
|
|
import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerAdapter; |
|
|
|
import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerAdapter; |
|
|
|
import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping; |
|
|
|
import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping; |
|
|
|
import org.springframework.web.reactive.result.method.annotation.ResponseBodyResultHandler; |
|
|
|
import org.springframework.web.reactive.result.method.annotation.ResponseBodyResultHandler; |
|
|
|
|
|
|
|
import org.springframework.web.reactive.result.method.annotation.ResponseEntityExceptionHandler; |
|
|
|
|
|
|
|
import org.springframework.web.reactive.result.method.annotation.ResponseEntityResultHandler; |
|
|
|
import org.springframework.web.server.NotAcceptableStatusException; |
|
|
|
import org.springframework.web.server.NotAcceptableStatusException; |
|
|
|
import org.springframework.web.server.ResponseStatusException; |
|
|
|
import org.springframework.web.server.ResponseStatusException; |
|
|
|
import org.springframework.web.server.ServerWebExchange; |
|
|
|
import org.springframework.web.server.ServerWebExchange; |
|
|
|
@ -48,6 +57,7 @@ import org.springframework.web.server.WebExceptionHandler; |
|
|
|
import org.springframework.web.server.WebHandler; |
|
|
|
import org.springframework.web.server.WebHandler; |
|
|
|
import org.springframework.web.server.handler.ExceptionHandlingWebHandler; |
|
|
|
import org.springframework.web.server.handler.ExceptionHandlingWebHandler; |
|
|
|
import org.springframework.web.testfixture.http.server.reactive.MockServerHttpRequest; |
|
|
|
import org.springframework.web.testfixture.http.server.reactive.MockServerHttpRequest; |
|
|
|
|
|
|
|
import org.springframework.web.testfixture.http.server.reactive.MockServerHttpResponse; |
|
|
|
import org.springframework.web.testfixture.server.MockServerWebExchange; |
|
|
|
import org.springframework.web.testfixture.server.MockServerWebExchange; |
|
|
|
|
|
|
|
|
|
|
|
import static org.assertj.core.api.Assertions.assertThat; |
|
|
|
import static org.assertj.core.api.Assertions.assertThat; |
|
|
|
@ -69,10 +79,11 @@ public class DispatcherHandlerErrorTests { |
|
|
|
|
|
|
|
|
|
|
|
@BeforeEach |
|
|
|
@BeforeEach |
|
|
|
public void setup() { |
|
|
|
public void setup() { |
|
|
|
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); |
|
|
|
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); |
|
|
|
ctx.register(TestConfig.class); |
|
|
|
context.register(TestConfig.class); |
|
|
|
ctx.refresh(); |
|
|
|
context.refresh(); |
|
|
|
this.dispatcherHandler = new DispatcherHandler(ctx); |
|
|
|
|
|
|
|
|
|
|
|
this.dispatcherHandler = new DispatcherHandler(context); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -94,6 +105,28 @@ public class DispatcherHandlerErrorTests { |
|
|
|
StepVerifier.create(mono).consumeErrorWith(ex -> assertThat(ex).isNotSameAs(exceptionRef.get())).verify(); |
|
|
|
StepVerifier.create(mono).consumeErrorWith(ex -> assertThat(ex).isNotSameAs(exceptionRef.get())).verify(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
|
|
|
public void noStaticResource() { |
|
|
|
|
|
|
|
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); |
|
|
|
|
|
|
|
context.register(StaticResourceConfig.class); |
|
|
|
|
|
|
|
context.refresh(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MockServerHttpRequest request = MockServerHttpRequest.get("/resources/non-existing").build(); |
|
|
|
|
|
|
|
MockServerWebExchange exchange = MockServerWebExchange.from(request); |
|
|
|
|
|
|
|
new DispatcherHandler(context).handle(exchange).block(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MockServerHttpResponse response = exchange.getResponse(); |
|
|
|
|
|
|
|
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND); |
|
|
|
|
|
|
|
assertThat(response.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_PROBLEM_JSON); |
|
|
|
|
|
|
|
assertThat(response.getBodyAsString().block()).isEqualTo(""" |
|
|
|
|
|
|
|
{"type":"about:blank",\ |
|
|
|
|
|
|
|
"title":"Not Found",\ |
|
|
|
|
|
|
|
"status":404,\ |
|
|
|
|
|
|
|
"detail":"No static resource non-existing.",\ |
|
|
|
|
|
|
|
"instance":"/resources/non-existing"}\ |
|
|
|
|
|
|
|
"""); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
@Test |
|
|
|
public void controllerReturnsMonoError() { |
|
|
|
public void controllerReturnsMonoError() { |
|
|
|
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/error-signal")); |
|
|
|
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/error-signal")); |
|
|
|
@ -223,6 +256,50 @@ public class DispatcherHandlerErrorTests { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Configuration |
|
|
|
|
|
|
|
@SuppressWarnings({"unused", "WeakerAccess"}) |
|
|
|
|
|
|
|
static class StaticResourceConfig { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Bean |
|
|
|
|
|
|
|
public SimpleUrlHandlerMapping resourceMapping(ResourceWebHandler resourceWebHandler) { |
|
|
|
|
|
|
|
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping(); |
|
|
|
|
|
|
|
mapping.setUrlMap(Map.of("/resources/**", resourceWebHandler)); |
|
|
|
|
|
|
|
return mapping; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Bean |
|
|
|
|
|
|
|
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() { |
|
|
|
|
|
|
|
return new RequestMappingHandlerAdapter(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Bean |
|
|
|
|
|
|
|
public SimpleHandlerAdapter simpleHandlerAdapter() { |
|
|
|
|
|
|
|
return new SimpleHandlerAdapter(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Bean |
|
|
|
|
|
|
|
public ResourceWebHandler resourceWebHandler() { |
|
|
|
|
|
|
|
return new ResourceWebHandler(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Bean |
|
|
|
|
|
|
|
public ResponseEntityResultHandler responseEntityResultHandler() { |
|
|
|
|
|
|
|
ServerCodecConfigurer configurer = ServerCodecConfigurer.create(); |
|
|
|
|
|
|
|
return new ResponseEntityResultHandler(configurer.getWriters(), new HeaderContentTypeResolver()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Bean |
|
|
|
|
|
|
|
GlobalExceptionHandler globalExceptionHandler() { |
|
|
|
|
|
|
|
return new GlobalExceptionHandler(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ControllerAdvice |
|
|
|
|
|
|
|
private static class GlobalExceptionHandler extends ResponseEntityExceptionHandler { |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static class ServerError500ExceptionHandler implements WebExceptionHandler { |
|
|
|
private static class ServerError500ExceptionHandler implements WebExceptionHandler { |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
|