@ -1,5 +1,5 @@
@@ -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" ) ;
* you may not use this file except in compliance with the License .
@ -19,6 +19,7 @@ package org.springframework.web.reactive;
@@ -19,6 +19,7 @@ package org.springframework.web.reactive;
import java.time.Duration ;
import java.util.Collections ;
import java.util.List ;
import java.util.Map ;
import java.util.concurrent.atomic.AtomicReference ;
import org.junit.jupiter.api.BeforeEach ;
@ -32,15 +33,23 @@ import org.springframework.context.annotation.Bean;
@@ -32,15 +33,23 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration ;
import org.springframework.core.codec.CharSequenceEncoder ;
import org.springframework.http.HttpStatus ;
import org.springframework.http.MediaType ;
import org.springframework.http.codec.EncoderHttpMessageWriter ;
import org.springframework.http.codec.ServerCodecConfigurer ;
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.RequestMapping ;
import org.springframework.web.bind.annotation.ResponseBody ;
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.RequestMappingHandlerMapping ;
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.ResponseStatusException ;
import org.springframework.web.server.ServerWebExchange ;
@ -48,6 +57,7 @@ import org.springframework.web.server.WebExceptionHandler;
@@ -48,6 +57,7 @@ import org.springframework.web.server.WebExceptionHandler;
import org.springframework.web.server.WebHandler ;
import org.springframework.web.server.handler.ExceptionHandlingWebHandler ;
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 static org.assertj.core.api.Assertions.assertThat ;
@ -69,10 +79,11 @@ public class DispatcherHandlerErrorTests {
@@ -69,10 +79,11 @@ public class DispatcherHandlerErrorTests {
@BeforeEach
public void setup ( ) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext ( ) ;
ctx . register ( TestConfig . class ) ;
ctx . refresh ( ) ;
this . dispatcherHandler = new DispatcherHandler ( ctx ) ;
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext ( ) ;
context . register ( TestConfig . class ) ;
context . refresh ( ) ;
this . dispatcherHandler = new DispatcherHandler ( context ) ;
}
@ -94,6 +105,28 @@ public class DispatcherHandlerErrorTests {
@@ -94,6 +105,28 @@ public class DispatcherHandlerErrorTests {
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
public void controllerReturnsMonoError ( ) {
MockServerWebExchange exchange = MockServerWebExchange . from ( MockServerHttpRequest . get ( "/error-signal" ) ) ;
@ -223,6 +256,50 @@ public class DispatcherHandlerErrorTests {
@@ -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 {
@Override