From 9a04bf2c2c2c3de8aebd6bee0ea7dd92dda20909 Mon Sep 17 00:00:00 2001 From: jacques Date: Tue, 22 May 2018 12:07:45 -0400 Subject: [PATCH 1/3] Code update for Spring RestTemplate Exception Handling article. --- spring-rest-simple/pom.xml | 10 +++- .../java/org/baeldung/config/WebConfig.java | 6 +-- .../web/exception/NotFoundException.java | 4 ++ .../RestTemplateResponseErrorHandler.java | 53 ++++++++++++++++++ .../main/java/org/baeldung/web/model/Bar.java | 22 ++++++++ .../web/service/BarConsumerService.java | 24 +++++++++ ...teResponseErrorHandlerIntegrationTest.java | 54 +++++++++++++++++++ 7 files changed, 168 insertions(+), 5 deletions(-) create mode 100644 spring-rest-simple/src/main/java/org/baeldung/web/exception/NotFoundException.java create mode 100644 spring-rest-simple/src/main/java/org/baeldung/web/handler/RestTemplateResponseErrorHandler.java create mode 100644 spring-rest-simple/src/main/java/org/baeldung/web/model/Bar.java create mode 100644 spring-rest-simple/src/main/java/org/baeldung/web/service/BarConsumerService.java create mode 100644 spring-rest-simple/src/test/java/org/baeldung/web/handler/RestTemplateResponseErrorHandlerIntegrationTest.java diff --git a/spring-rest-simple/pom.xml b/spring-rest-simple/pom.xml index 1c6c6e1044..c8c9c1ae0a 100644 --- a/spring-rest-simple/pom.xml +++ b/spring-rest-simple/pom.xml @@ -31,8 +31,14 @@ org.springframework.boot - spring-boot-test + spring-boot-starter-test + test + + + + + @@ -240,7 +246,7 @@ cargo-maven2-plugin ${cargo-maven2-plugin.version} - true + tomcat8x embedded diff --git a/spring-rest-simple/src/main/java/org/baeldung/config/WebConfig.java b/spring-rest-simple/src/main/java/org/baeldung/config/WebConfig.java index ec92ad8349..309a36609a 100644 --- a/spring-rest-simple/src/main/java/org/baeldung/config/WebConfig.java +++ b/spring-rest-simple/src/main/java/org/baeldung/config/WebConfig.java @@ -1,8 +1,5 @@ package org.baeldung.config; -import java.text.SimpleDateFormat; -import java.util.List; - import org.baeldung.config.converter.KryoHttpMessageConverter; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @@ -19,6 +16,9 @@ import org.springframework.web.servlet.config.annotation.ContentNegotiationConfi import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; +import java.text.SimpleDateFormat; +import java.util.List; + /* * Please note that main web configuration is in src/main/webapp/WEB-INF/api-servlet.xml */ diff --git a/spring-rest-simple/src/main/java/org/baeldung/web/exception/NotFoundException.java b/spring-rest-simple/src/main/java/org/baeldung/web/exception/NotFoundException.java new file mode 100644 index 0000000000..5b4d80a659 --- /dev/null +++ b/spring-rest-simple/src/main/java/org/baeldung/web/exception/NotFoundException.java @@ -0,0 +1,4 @@ +package org.baeldung.web.exception; + +public class NotFoundException extends RuntimeException { +} diff --git a/spring-rest-simple/src/main/java/org/baeldung/web/handler/RestTemplateResponseErrorHandler.java b/spring-rest-simple/src/main/java/org/baeldung/web/handler/RestTemplateResponseErrorHandler.java new file mode 100644 index 0000000000..1fb75fe21a --- /dev/null +++ b/spring-rest-simple/src/main/java/org/baeldung/web/handler/RestTemplateResponseErrorHandler.java @@ -0,0 +1,53 @@ +package org.baeldung.web.handler; + +import org.baeldung.web.exception.NotFoundException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.stereotype.Component; +import org.springframework.web.client.ResponseErrorHandler; + +import java.io.IOException; + +@Component +public class RestTemplateResponseErrorHandler implements ResponseErrorHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(RestTemplateResponseErrorHandler.class); + + + @Override + public boolean hasError(ClientHttpResponse httpResponse) throws IOException { + return (httpResponse + .getStatusCode() + .series() == HttpStatus.Series.CLIENT_ERROR || httpResponse + .getStatusCode() + .series() == HttpStatus.Series.SERVER_ERROR); + } + + @Override + public void handleError(ClientHttpResponse httpResponse) throws IOException { + if (httpResponse + .getStatusCode() + .series() == HttpStatus.Series.SERVER_ERROR) { + this.handleServerError(httpResponse); + } else if (httpResponse + .getStatusCode() + .series() == HttpStatus.Series.CLIENT_ERROR) { + this.handleClientError(httpResponse); + } + } + + private void handleServerError(ClientHttpResponse httpResponse) { + //Handle Server specific errors + } + + private void handleClientError(ClientHttpResponse httpResponse) throws IOException { + //Handle Client specific errors + if (httpResponse.getStatusCode() == HttpStatus.NOT_FOUND) { + //Log details here... + LOGGER.info("Throwing NotFoundException..."); + throw new NotFoundException(); + } + } +} diff --git a/spring-rest-simple/src/main/java/org/baeldung/web/model/Bar.java b/spring-rest-simple/src/main/java/org/baeldung/web/model/Bar.java new file mode 100644 index 0000000000..474e2070a5 --- /dev/null +++ b/spring-rest-simple/src/main/java/org/baeldung/web/model/Bar.java @@ -0,0 +1,22 @@ +package org.baeldung.web.model; + +public class Bar { + private String id; + private String name; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/spring-rest-simple/src/main/java/org/baeldung/web/service/BarConsumerService.java b/spring-rest-simple/src/main/java/org/baeldung/web/service/BarConsumerService.java new file mode 100644 index 0000000000..09e8c06e13 --- /dev/null +++ b/spring-rest-simple/src/main/java/org/baeldung/web/service/BarConsumerService.java @@ -0,0 +1,24 @@ +package org.baeldung.web.service; + +import org.baeldung.web.handler.RestTemplateResponseErrorHandler; +import org.baeldung.web.model.Bar; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + + +@Service +public class BarConsumerService { + + + @Autowired RestTemplateBuilder restTemplateBuilder; + + public Bar fetchBarById(String barId) { + RestTemplate restTemplate = restTemplateBuilder + .errorHandler(new RestTemplateResponseErrorHandler()) + .build(); + return restTemplate.getForObject("/bars/4242", Bar.class); + } + +} diff --git a/spring-rest-simple/src/test/java/org/baeldung/web/handler/RestTemplateResponseErrorHandlerIntegrationTest.java b/spring-rest-simple/src/test/java/org/baeldung/web/handler/RestTemplateResponseErrorHandlerIntegrationTest.java new file mode 100644 index 0000000000..94faaaae55 --- /dev/null +++ b/spring-rest-simple/src/test/java/org/baeldung/web/handler/RestTemplateResponseErrorHandlerIntegrationTest.java @@ -0,0 +1,54 @@ +package org.baeldung.web.handler; + +import org.baeldung.web.dto.Bazz; +import org.baeldung.web.exception.NotFoundException; +import org.baeldung.web.model.Bar; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.client.RestClientTest; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.client.ExpectedCount; +import org.springframework.test.web.client.MockRestServiceServer; +import org.springframework.web.client.RestTemplate; + +import static org.springframework.test.web.client.match.MockRestRequestMatchers.method; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus; + +@RunWith(SpringRunner.class) +@ContextConfiguration(classes = {NotFoundException.class, Bar.class}) +@RestClientTest +public class RestTemplateResponseErrorHandlerIntegrationTest { + + private static final Logger LOGGER = LoggerFactory.getLogger(RestTemplateResponseErrorHandler.class); + + @Autowired private MockRestServiceServer server; + @Autowired private RestTemplateBuilder builder; + + + @Test(expected = NotFoundException.class) + public void givenCallToRemoteApi_when404ErrorReceived_throwNotFoundException() { + Assert.assertNotNull(this.builder); + Assert.assertNotNull(this.server); + + RestTemplate restTemplate = this.builder + .errorHandler(new RestTemplateResponseErrorHandler()) + .build(); + + this.server + .expect(ExpectedCount.once(), requestTo("/bars/4242")) + .andExpect(method(HttpMethod.GET)) + .andRespond(withStatus(HttpStatus.NOT_FOUND)); + + Bar response = restTemplate.getForObject("/bars/4242", Bar.class); + this.server.verify(); + } +} \ No newline at end of file From 635224a40422ca655085605a1b6a2e390033c00a Mon Sep 17 00:00:00 2001 From: Tom Hombergs Date: Tue, 22 May 2018 22:40:30 +0200 Subject: [PATCH 2/3] removed commented-out lines --- spring-rest-simple/pom.xml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/spring-rest-simple/pom.xml b/spring-rest-simple/pom.xml index c8c9c1ae0a..e774dc6ad9 100644 --- a/spring-rest-simple/pom.xml +++ b/spring-rest-simple/pom.xml @@ -34,11 +34,6 @@ spring-boot-starter-test test - - - - - From 1aaa12eca63d9161b9331987b914dff7d6cf3e8d Mon Sep 17 00:00:00 2001 From: jacques Date: Wed, 23 May 2018 08:28:37 -0400 Subject: [PATCH 3/3] Corrections implementation. --- .../RestTemplateResponseErrorHandler.java | 36 ++++++----------- .../web/service/BarConsumerService.java | 10 +++-- ...teResponseErrorHandlerIntegrationTest.java | 40 ++++++++----------- 3 files changed, 36 insertions(+), 50 deletions(-) diff --git a/spring-rest-simple/src/main/java/org/baeldung/web/handler/RestTemplateResponseErrorHandler.java b/spring-rest-simple/src/main/java/org/baeldung/web/handler/RestTemplateResponseErrorHandler.java index 1fb75fe21a..b1b87e89a5 100644 --- a/spring-rest-simple/src/main/java/org/baeldung/web/handler/RestTemplateResponseErrorHandler.java +++ b/spring-rest-simple/src/main/java/org/baeldung/web/handler/RestTemplateResponseErrorHandler.java @@ -1,8 +1,6 @@ package org.baeldung.web.handler; import org.baeldung.web.exception.NotFoundException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; import org.springframework.http.client.ClientHttpResponse; import org.springframework.stereotype.Component; @@ -11,13 +9,13 @@ import org.springframework.web.client.ResponseErrorHandler; import java.io.IOException; @Component -public class RestTemplateResponseErrorHandler implements ResponseErrorHandler { - - private static final Logger LOGGER = LoggerFactory.getLogger(RestTemplateResponseErrorHandler.class); - +public class RestTemplateResponseErrorHandler + implements ResponseErrorHandler { @Override - public boolean hasError(ClientHttpResponse httpResponse) throws IOException { + public boolean hasError(ClientHttpResponse httpResponse) + throws IOException { + return (httpResponse .getStatusCode() .series() == HttpStatus.Series.CLIENT_ERROR || httpResponse @@ -26,28 +24,20 @@ public class RestTemplateResponseErrorHandler implements ResponseErrorHandler { } @Override - public void handleError(ClientHttpResponse httpResponse) throws IOException { + public void handleError(ClientHttpResponse httpResponse) + throws IOException { + if (httpResponse .getStatusCode() .series() == HttpStatus.Series.SERVER_ERROR) { - this.handleServerError(httpResponse); + //Handle SERVER_ERROR } else if (httpResponse .getStatusCode() .series() == HttpStatus.Series.CLIENT_ERROR) { - this.handleClientError(httpResponse); - } - } - - private void handleServerError(ClientHttpResponse httpResponse) { - //Handle Server specific errors - } - - private void handleClientError(ClientHttpResponse httpResponse) throws IOException { - //Handle Client specific errors - if (httpResponse.getStatusCode() == HttpStatus.NOT_FOUND) { - //Log details here... - LOGGER.info("Throwing NotFoundException..."); - throw new NotFoundException(); + //Handle CLIENT_ERROR + if (httpResponse.getStatusCode() == HttpStatus.NOT_FOUND) { + throw new NotFoundException(); + } } } } diff --git a/spring-rest-simple/src/main/java/org/baeldung/web/service/BarConsumerService.java b/spring-rest-simple/src/main/java/org/baeldung/web/service/BarConsumerService.java index 09e8c06e13..4188677b4f 100644 --- a/spring-rest-simple/src/main/java/org/baeldung/web/service/BarConsumerService.java +++ b/spring-rest-simple/src/main/java/org/baeldung/web/service/BarConsumerService.java @@ -7,17 +7,19 @@ import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; - @Service public class BarConsumerService { + private RestTemplate restTemplate; - @Autowired RestTemplateBuilder restTemplateBuilder; - - public Bar fetchBarById(String barId) { + @Autowired + public BarConsumerService(RestTemplateBuilder restTemplateBuilder) { RestTemplate restTemplate = restTemplateBuilder .errorHandler(new RestTemplateResponseErrorHandler()) .build(); + } + + public Bar fetchBarById(String barId) { return restTemplate.getForObject("/bars/4242", Bar.class); } diff --git a/spring-rest-simple/src/test/java/org/baeldung/web/handler/RestTemplateResponseErrorHandlerIntegrationTest.java b/spring-rest-simple/src/test/java/org/baeldung/web/handler/RestTemplateResponseErrorHandlerIntegrationTest.java index 94faaaae55..2dfa81f441 100644 --- a/spring-rest-simple/src/test/java/org/baeldung/web/handler/RestTemplateResponseErrorHandlerIntegrationTest.java +++ b/spring-rest-simple/src/test/java/org/baeldung/web/handler/RestTemplateResponseErrorHandlerIntegrationTest.java @@ -1,13 +1,10 @@ package org.baeldung.web.handler; -import org.baeldung.web.dto.Bazz; import org.baeldung.web.exception.NotFoundException; import org.baeldung.web.model.Bar; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.client.RestClientTest; import org.springframework.boot.web.client.RestTemplateBuilder; @@ -24,31 +21,28 @@ import static org.springframework.test.web.client.match.MockRestRequestMatchers. import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus; @RunWith(SpringRunner.class) -@ContextConfiguration(classes = {NotFoundException.class, Bar.class}) +@ContextConfiguration(classes = { NotFoundException.class, Bar.class }) @RestClientTest public class RestTemplateResponseErrorHandlerIntegrationTest { - private static final Logger LOGGER = LoggerFactory.getLogger(RestTemplateResponseErrorHandler.class); + @Autowired private MockRestServiceServer server; + @Autowired private RestTemplateBuilder builder; - @Autowired private MockRestServiceServer server; - @Autowired private RestTemplateBuilder builder; + @Test(expected = NotFoundException.class) + public void givenRemoteApiCall_when404Error_thenThrowNotFound() { + Assert.assertNotNull(this.builder); + Assert.assertNotNull(this.server); + RestTemplate restTemplate = this.builder + .errorHandler(new RestTemplateResponseErrorHandler()) + .build(); - @Test(expected = NotFoundException.class) - public void givenCallToRemoteApi_when404ErrorReceived_throwNotFoundException() { - Assert.assertNotNull(this.builder); - Assert.assertNotNull(this.server); + this.server + .expect(ExpectedCount.once(), requestTo("/bars/4242")) + .andExpect(method(HttpMethod.GET)) + .andRespond(withStatus(HttpStatus.NOT_FOUND)); - RestTemplate restTemplate = this.builder - .errorHandler(new RestTemplateResponseErrorHandler()) - .build(); - - this.server - .expect(ExpectedCount.once(), requestTo("/bars/4242")) - .andExpect(method(HttpMethod.GET)) - .andRespond(withStatus(HttpStatus.NOT_FOUND)); - - Bar response = restTemplate.getForObject("/bars/4242", Bar.class); - this.server.verify(); - } + Bar response = restTemplate.getForObject("/bars/4242", Bar.class); + this.server.verify(); + } } \ No newline at end of file