diff --git a/belgif-rest-problem-it/belgif-rest-problem-spring-boot-3-it/src/main/java/io/github/belgif/rest/problem/Client.java b/belgif-rest-problem-it/belgif-rest-problem-spring-boot-3-it/src/main/java/io/github/belgif/rest/problem/Client.java
index 5be571e9..0a4f64af 100644
--- a/belgif-rest-problem-it/belgif-rest-problem-spring-boot-3-it/src/main/java/io/github/belgif/rest/problem/Client.java
+++ b/belgif-rest-problem-it/belgif-rest-problem-spring-boot-3-it/src/main/java/io/github/belgif/rest/problem/Client.java
@@ -2,6 +2,6 @@
public enum Client {
- REST_TEMPLATE, WEB_CLIENT
+ REST_TEMPLATE, WEB_CLIENT, REST_CLIENT
}
diff --git a/belgif-rest-problem-it/belgif-rest-problem-spring-boot-3-it/src/main/java/io/github/belgif/rest/problem/FrontendController.java b/belgif-rest-problem-it/belgif-rest-problem-spring-boot-3-it/src/main/java/io/github/belgif/rest/problem/FrontendController.java
index e4d0cbf4..6761efd6 100644
--- a/belgif-rest-problem-it/belgif-rest-problem-spring-boot-3-it/src/main/java/io/github/belgif/rest/problem/FrontendController.java
+++ b/belgif-rest-problem-it/belgif-rest-problem-spring-boot-3-it/src/main/java/io/github/belgif/rest/problem/FrontendController.java
@@ -11,6 +11,7 @@
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
+import org.springframework.web.client.RestClient;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.reactive.function.client.WebClient;
@@ -33,13 +34,20 @@ public class FrontendController implements ControllerInterface {
private final WebClient.Builder webClientBuilder;
+ private final RestClient.Builder restClientBuilder;
+
private RestTemplate restTemplate;
private WebClient webClient;
- public FrontendController(RestTemplateBuilder restTemplateBuilder, WebClient.Builder webClientBuilder) {
+ private RestClient restClient;
+
+ public FrontendController(RestTemplateBuilder restTemplateBuilder,
+ WebClient.Builder webClientBuilder,
+ RestClient.Builder restClientBuilder) {
this.restTemplateBuilder = restTemplateBuilder;
this.webClientBuilder = webClientBuilder;
+ this.restClientBuilder = restClientBuilder;
}
@EventListener
@@ -48,7 +56,11 @@ public void onApplicationEvent(ServletWebServerInitializedEvent event) {
.rootUri("http://localhost:" + event.getWebServer().getPort() + "/spring/backend")
.build();
this.webClient = webClientBuilder
- .baseUrl("http://localhost:" + event.getWebServer().getPort() + "/spring/backend").build();
+ .baseUrl("http://localhost:" + event.getWebServer().getPort() + "/spring/backend")
+ .build();
+ this.restClient = restClientBuilder
+ .baseUrl("http://localhost:" + event.getWebServer().getPort() + "/spring/backend")
+ .build();
}
@GetMapping("/badRequest")
@@ -90,6 +102,8 @@ public void badRequestFromBackend(@RequestParam("client") Client client) {
restTemplate.getForObject("/badRequest", String.class);
} else if (client == Client.WEB_CLIENT) {
webClient.get().uri("/badRequest").retrieve().toEntity(String.class).block();
+ } else if (client == Client.REST_CLIENT) {
+ restClient.get().uri("/badRequest").retrieve().toEntity(String.class);
}
throw new IllegalStateException(ILLEGAL_STATE_MESSAGE_PREFIX + client);
} catch (BadRequestProblem e) {
@@ -105,6 +119,8 @@ public void customFromBackend(@RequestParam("client") Client client) {
restTemplate.getForObject("/custom", String.class);
} else if (client == Client.WEB_CLIENT) {
webClient.get().uri("/custom").retrieve().toEntity(String.class).block();
+ } else if (client == Client.REST_CLIENT) {
+ restClient.get().uri("/custom").retrieve().toEntity(String.class);
}
throw new IllegalStateException(ILLEGAL_STATE_MESSAGE_PREFIX + client);
} catch (CustomProblem e) {
@@ -120,6 +136,8 @@ public void unmappedFromBackend(@RequestParam("client") Client client) {
restTemplate.getForObject("/unmapped", String.class);
} else if (client == Client.WEB_CLIENT) {
webClient.get().uri("/unmapped").retrieve().toEntity(String.class).block();
+ } else if (client == Client.REST_CLIENT) {
+ restClient.get().uri("/unmapped").retrieve().toEntity(String.class);
}
throw new IllegalStateException(ILLEGAL_STATE_MESSAGE_PREFIX + client);
} catch (DefaultProblem e) {
diff --git a/belgif-rest-problem-spring-boot-3/pom.xml b/belgif-rest-problem-spring-boot-3/pom.xml
index defcddcc..00e9539b 100644
--- a/belgif-rest-problem-spring-boot-3/pom.xml
+++ b/belgif-rest-problem-spring-boot-3/pom.xml
@@ -46,6 +46,11 @@
spring-webmvc
provided
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ provided
+
jakarta.platform
jakarta.jakartaee-api
diff --git a/belgif-rest-problem-spring-boot-3/src/main/java/io/github/belgif/rest/problem/spring/ProblemRestClientCustomizer.java b/belgif-rest-problem-spring-boot-3/src/main/java/io/github/belgif/rest/problem/spring/ProblemRestClientCustomizer.java
new file mode 100644
index 00000000..0bda31cf
--- /dev/null
+++ b/belgif-rest-problem-spring-boot-3/src/main/java/io/github/belgif/rest/problem/spring/ProblemRestClientCustomizer.java
@@ -0,0 +1,26 @@
+package io.github.belgif.rest.problem.spring;
+
+import org.springframework.boot.web.client.RestClientCustomizer;
+import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestClient;
+
+/**
+ * RestClientCustomizer that registers the {@link ProblemResponseErrorHandler}.
+ *
+ * @see ProblemResponseErrorHandler
+ */
+@Component
+public class ProblemRestClientCustomizer implements RestClientCustomizer {
+
+ private final ProblemResponseErrorHandler errorHandler;
+
+ public ProblemRestClientCustomizer(ProblemResponseErrorHandler errorHandler) {
+ this.errorHandler = errorHandler;
+ }
+
+ @Override
+ public void customize(RestClient.Builder restClientBuilder) {
+ restClientBuilder.defaultStatusHandler(errorHandler);
+ }
+
+}
diff --git a/belgif-rest-problem-spring-boot-3/src/test/java/io/github/belgif/rest/problem/spring/ProblemRestClientCustomizerTest.java b/belgif-rest-problem-spring-boot-3/src/test/java/io/github/belgif/rest/problem/spring/ProblemRestClientCustomizerTest.java
new file mode 100644
index 00000000..5b6e387e
--- /dev/null
+++ b/belgif-rest-problem-spring-boot-3/src/test/java/io/github/belgif/rest/problem/spring/ProblemRestClientCustomizerTest.java
@@ -0,0 +1,26 @@
+package io.github.belgif.rest.problem.spring;
+
+import static org.assertj.core.api.Assertions.*;
+
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.test.util.ReflectionTestUtils;
+import org.springframework.web.client.RestClient;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+class ProblemRestClientCustomizerTest {
+
+ @Test
+ void customize() {
+ ProblemResponseErrorHandler handler = new ProblemResponseErrorHandler(new ObjectMapper());
+ ProblemRestClientCustomizer customizer = new ProblemRestClientCustomizer(handler);
+ RestClient.Builder builder = RestClient.builder();
+ customizer.customize(builder);
+
+ List> statusHandlers = (List>) ReflectionTestUtils.getField(builder, "statusHandlers");
+ assertThat(statusHandlers).hasSize(1);
+ }
+
+}
diff --git a/src/main/asciidoc/index.adoc b/src/main/asciidoc/index.adoc
index ce1630b8..4321c71d 100644
--- a/src/main/asciidoc/index.adoc
+++ b/src/main/asciidoc/index.adoc
@@ -39,6 +39,7 @@ To benefit from Spring Boot 2.x or 3.x specific features, replace dependencies t
*belgif-rest-problem-spring-boot-3:*
* Map NoResourceFoundException to 404 `urn:problem-type:belgif:resourceNotFound`
+* Added support for https://docs.spring.io/spring-framework/reference/integration/rest-clients.html#rest-restclient[RestClient] API
=== Version 0.4
@@ -348,7 +349,7 @@ io.github.belgif.rest.problem.scan-additional-problem-packages=com.acme.custom
* *BeanValidationExceptionsHandler:* an exception handler for RestControllers that converts bean validation related exceptions to HTTP 400 BadRequestProblem.
* *RoutingExceptionsHandler:* an exception handler for RestControllers that converts routing related validation exceptions to HTTP 400 BadRequestProblem.
* *ProblemResponseErrorHandler:* a RestTemplate error handler that converts problem responses to Problem exceptions.
-* *ProblemRestTemplateCustomizer:* a RestTemplateCustomizer that registers the ProblemResponseErrorHandler
+* *ProblemRestTemplateCustomizer:* a RestTemplateCustomizer that registers the ProblemResponseErrorHandler.
* *ProblemWebClientCustomizer:* a WebClientCustomizer that registers a filter that converts problem responses to Problem exceptions.
This handles integration with the https://docs.spring.io/spring-framework/reference/web/webflux-webclient.html[Reactive WebClient].
@@ -365,6 +366,7 @@ Rather than depending on <> directly, Spring Boot 2.
Rather than depending on <> directly, Spring Boot 3.x users are recommended to depend on `belgif-rest-problem-spring-boot-3`, which adds some Spring Boot 3.x specific integrations:
* *NoResourceFoundExceptionHandler:* an exception handler for RestControllers that converts NoResourceFoundException to HTTP 404 ResourceNotFoundProblem.
+* *ProblemRestClientCustomizer:* a RestClientCustomizer that registers the ProblemResponseErrorHandler.
[[code-generators]]
== Code generators