JAVA-25542 Check code of spring-reactive ebook (#14880)
Co-authored-by: timis1 <noreplay@yahoo.com>
This commit is contained in:
+18
@@ -0,0 +1,18 @@
|
||||
package com.baeldung.reactive.errorhandling;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration;
|
||||
|
||||
@SpringBootApplication(exclude = {
|
||||
MongoReactiveAutoConfiguration.class,
|
||||
ReactiveSecurityAutoConfiguration.class,
|
||||
ReactiveUserDetailsServiceAutoConfiguration.class })
|
||||
public class ErrorHandlingApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(ErrorHandlingApplication.class, args);
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package com.baeldung.reactive.errorhandling;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.web.error.ErrorAttributeOptions;
|
||||
import org.springframework.boot.web.reactive.error.DefaultErrorAttributes;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.reactive.function.server.ServerRequest;
|
||||
|
||||
@Component
|
||||
public class GlobalErrorAttributes extends DefaultErrorAttributes {
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getErrorAttributes(ServerRequest request, ErrorAttributeOptions options) {
|
||||
Map<String, Object> map = super.getErrorAttributes(request, options);
|
||||
map.put("status", HttpStatus.BAD_REQUEST);
|
||||
map.put("message", "please provide a name");
|
||||
return map;
|
||||
}
|
||||
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package com.baeldung.reactive.errorhandling;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.autoconfigure.web.WebProperties;
|
||||
import org.springframework.boot.autoconfigure.web.reactive.error.AbstractErrorWebExceptionHandler;
|
||||
import org.springframework.boot.web.error.ErrorAttributeOptions;
|
||||
import org.springframework.boot.web.reactive.error.ErrorAttributes;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.codec.ServerCodecConfigurer;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.reactive.function.BodyInserters;
|
||||
import org.springframework.web.reactive.function.server.RequestPredicates;
|
||||
import org.springframework.web.reactive.function.server.RouterFunction;
|
||||
import org.springframework.web.reactive.function.server.RouterFunctions;
|
||||
import org.springframework.web.reactive.function.server.ServerRequest;
|
||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@Component
|
||||
@Order(-2)
|
||||
public class GlobalErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler {
|
||||
|
||||
public GlobalErrorWebExceptionHandler(
|
||||
GlobalErrorAttributes g, ApplicationContext applicationContext,
|
||||
ServerCodecConfigurer serverCodecConfigurer) {
|
||||
super(g, new WebProperties.Resources(), applicationContext);
|
||||
super.setMessageWriters(serverCodecConfigurer.getWriters());
|
||||
super.setMessageReaders(serverCodecConfigurer.getReaders());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RouterFunction<ServerResponse> getRoutingFunction(final ErrorAttributes errorAttributes) {
|
||||
return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
|
||||
}
|
||||
|
||||
private Mono<ServerResponse> renderErrorResponse(final ServerRequest request) {
|
||||
|
||||
final Map<String, Object> errorPropertiesMap = getErrorAttributes(request, ErrorAttributeOptions.defaults());
|
||||
|
||||
return ServerResponse.status(HttpStatus.BAD_REQUEST)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.body(BodyInserters.fromValue(errorPropertiesMap));
|
||||
}
|
||||
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
package com.baeldung.reactive.errorhandling;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.reactive.function.server.ServerRequest;
|
||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@Component
|
||||
public class Handler {
|
||||
|
||||
public Mono<ServerResponse> handleWithErrorReturn(ServerRequest request) {
|
||||
return sayHello(request)
|
||||
.onErrorReturn("Hello, Stranger")
|
||||
.flatMap(s -> ServerResponse.ok()
|
||||
.contentType(MediaType.TEXT_PLAIN)
|
||||
.bodyValue(s));
|
||||
}
|
||||
|
||||
public Mono<ServerResponse> handleWithErrorResumeAndDynamicFallback(ServerRequest request) {
|
||||
return sayHello(request)
|
||||
.flatMap(s -> ServerResponse.ok()
|
||||
.contentType(MediaType.TEXT_PLAIN)
|
||||
.bodyValue(s))
|
||||
.onErrorResume(e -> (Mono.just("Hi, I looked around for your name but found: " + e.getMessage()))
|
||||
.flatMap(s -> ServerResponse.ok()
|
||||
.contentType(MediaType.TEXT_PLAIN)
|
||||
.bodyValue(s)));
|
||||
}
|
||||
|
||||
public Mono<ServerResponse> handleWithErrorResumeAndFallbackMethod(ServerRequest request) {
|
||||
return sayHello(request)
|
||||
.flatMap(s -> ServerResponse.ok()
|
||||
.contentType(MediaType.TEXT_PLAIN)
|
||||
.bodyValue(s))
|
||||
.onErrorResume(e -> sayHelloFallback()
|
||||
.flatMap(s -> ServerResponse.ok()
|
||||
.contentType(MediaType.TEXT_PLAIN)
|
||||
.bodyValue(s)));
|
||||
}
|
||||
|
||||
public Mono<ServerResponse> handleWithErrorResumeAndCustomException(ServerRequest request) {
|
||||
return ServerResponse.ok()
|
||||
.body(sayHello(request)
|
||||
.onErrorResume(e -> Mono.error(new NameRequiredException(
|
||||
HttpStatus.BAD_REQUEST,
|
||||
"please provide a name", e))), String.class);
|
||||
}
|
||||
|
||||
public Mono<ServerResponse> handleWithGlobalErrorHandler(ServerRequest request) {
|
||||
return ServerResponse.ok()
|
||||
.body(sayHello(request), String.class);
|
||||
}
|
||||
|
||||
private Mono<String> sayHello(ServerRequest request) {
|
||||
try {
|
||||
return Mono.just("Hello, " + request.queryParam("name").get());
|
||||
} catch (Exception e) {
|
||||
return Mono.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
private Mono<String> sayHelloFallback() {
|
||||
return Mono.just("Hello, Stranger");
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package com.baeldung.reactive.errorhandling;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
public class NameRequiredException extends ResponseStatusException {
|
||||
|
||||
public NameRequiredException(HttpStatus status, String message, Throwable e) {
|
||||
super(status, message, e);
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.baeldung.reactive.errorhandling;
|
||||
|
||||
import static org.springframework.http.MediaType.TEXT_PLAIN;
|
||||
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
|
||||
import static org.springframework.web.reactive.function.server.RequestPredicates.accept;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.reactive.function.server.RouterFunction;
|
||||
import org.springframework.web.reactive.function.server.RouterFunctions;
|
||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||
|
||||
@Component
|
||||
public class Router {
|
||||
|
||||
@Bean
|
||||
public RouterFunction<ServerResponse> routes(Handler handler) {
|
||||
return RouterFunctions
|
||||
.route(GET("/api/endpoint1").and(accept(TEXT_PLAIN)), handler::handleWithErrorReturn)
|
||||
.andRoute(GET("/api/endpoint2").and(accept(TEXT_PLAIN)), handler::handleWithErrorResumeAndFallbackMethod)
|
||||
.andRoute(GET("/api/endpoint3").and(accept(TEXT_PLAIN)), handler::handleWithErrorResumeAndDynamicFallback)
|
||||
.andRoute(GET("/api/endpoint4").and(accept(TEXT_PLAIN)), handler::handleWithErrorResumeAndCustomException)
|
||||
.andRoute(GET("/api/endpoint5").and(accept(TEXT_PLAIN)), handler::handleWithGlobalErrorHandler);
|
||||
}
|
||||
|
||||
}
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
package com.baeldung.reactive.errorhandling;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
@DirtiesContext
|
||||
@AutoConfigureWebTestClient(timeout = "10000")
|
||||
class ErrorHandlingIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
private WebTestClient webTestClient;
|
||||
|
||||
@Test
|
||||
void givenErrorReturn_whenUsernamePresent_thenOk() {
|
||||
|
||||
webTestClient.get()
|
||||
.uri("/api/endpoint1?name={username}", "Tony")
|
||||
.accept(MediaType.TEXT_PLAIN)
|
||||
.exchange()
|
||||
.expectBody(String.class).isEqualTo("Hello, Tony");
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenErrorReturn_whenNoUsername_thenOk() {
|
||||
|
||||
webTestClient.get()
|
||||
.uri("/api/endpoint1")
|
||||
.accept(MediaType.TEXT_PLAIN)
|
||||
.exchange()
|
||||
.expectBody(String.class).isEqualTo("Hello, Stranger");
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenResumeFallback_whenUsernamePresent_thenOk() {
|
||||
|
||||
webTestClient.get()
|
||||
.uri("/api/endpoint2?name={username}", "Tony")
|
||||
.accept(MediaType.TEXT_PLAIN)
|
||||
.exchange()
|
||||
.expectBody(String.class).isEqualTo("Hello, Tony");
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenResumeFallback_whenNoUsername_thenOk() {
|
||||
|
||||
webTestClient.get()
|
||||
.uri("/api/endpoint2")
|
||||
.accept(MediaType.TEXT_PLAIN)
|
||||
.exchange()
|
||||
.expectBody(String.class).isEqualTo("Hello, Stranger");
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenResumeDynamicValue_whenUsernamePresent_thenOk() {
|
||||
|
||||
webTestClient.get()
|
||||
.uri("/api/endpoint3?name={username}", "Tony")
|
||||
.accept(MediaType.TEXT_PLAIN)
|
||||
.exchange()
|
||||
.expectBody(String.class).isEqualTo("Hello, Tony");
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenResumeDynamicValue_whenNoUsername_thenOk() {
|
||||
|
||||
webTestClient.get()
|
||||
.uri("/api/endpoint3")
|
||||
.accept(MediaType.TEXT_PLAIN)
|
||||
.exchange()
|
||||
.expectBody(String.class).isEqualTo("Hi, I looked around for your name but found: No value present");
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenResumeRethrow_whenUsernamePresent_thenOk() {
|
||||
|
||||
webTestClient.get()
|
||||
.uri("/api/endpoint4?name={username}", "Tony")
|
||||
.accept(MediaType.TEXT_PLAIN)
|
||||
.exchange()
|
||||
.expectBody(String.class).isEqualTo("Hello, Tony");
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenResumeRethrow_whenNoUsername_thenOk() {
|
||||
|
||||
webTestClient.get()
|
||||
.uri("/api/endpoint4")
|
||||
.accept(MediaType.TEXT_PLAIN)
|
||||
.exchange()
|
||||
.expectStatus().isBadRequest()
|
||||
.expectHeader().contentType(MediaType.APPLICATION_JSON)
|
||||
.expectBody().jsonPath("$.message").isEqualTo("please provide a name");
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenGlobalErrorHandling_whenUsernamePresent_thenOk() {
|
||||
|
||||
webTestClient.get()
|
||||
.uri("/api/endpoint5?name={username}", "Tony")
|
||||
.accept(MediaType.TEXT_PLAIN)
|
||||
.exchange()
|
||||
.expectBody(String.class).isEqualTo("Hello, Tony");
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenGlobalErrorHandling_whenNoUsername_thenOk() {
|
||||
|
||||
webTestClient.get()
|
||||
.uri("/api/endpoint5")
|
||||
.accept(MediaType.TEXT_PLAIN)
|
||||
.exchange()
|
||||
.expectStatus().isBadRequest()
|
||||
.expectHeader().contentType(MediaType.APPLICATION_JSON)
|
||||
.expectBody().jsonPath("$.message").isEqualTo("please provide a name");
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user