Handle REST Service in SpringBoot - java

I have below code use to POST JSON object to the following URL
HttpEntity messageEntity = new HttpEntity(message, buildHttpHeaders(getTerminalId()));
String theUrl = "http://123.433.234.12/receive";
try {
System.out.println("In try block");
ResponseEntity<Dto> responseEntity= restTemplate.exchange(theUrl, HttpMethod.POST, messageEntity, Dto.class);
} catch (HttpStatusCodeException ex) {
// get http status code
}
If the URL is invalid or service unavailable, I want it throw error status code like 404 or 503. Unfortunatelly it will always stop at the try block..Is there a way to solve that ?
Output
In try block
Edit
String theUrl = "http://123.433.234.12/receive" + transactionId; //invalid Id
try {
System.out.println("=========start=========");
ResponseEntity<Dto> responseEntity= restTemplate.exchange(theUrl, HttpMethod.POST, messageEntity, Dto.class);
System.out.println("=========end=========");
} catch (HttpStatusCodeException ex) {
String a = ex.getStatusCode().toString();
System.out.println(a);
}
Output
=========start=========
2017-09-22 14:54:54 [xles-server-ThreadPool.PooledThread-0-running] ERROR c.r.abc.jpos.JposRequestListener - Error HttpStatusCode 500org.springframework.web.client.HttpServerErrorException: 500 null
It stop and not display ========end ======== or any status code in catch block
Valid url
http://abc0/receive/hello
If I change to
http://abc0/recei/hello
I will get 404 in catch block, it look fine. But when I change to another url that not exits,example
http://123.433.234.12/receive
it is in try block .Why ????

With reference to this doc, you should catch RestClientException instead of just HttpStatusCodeException.
If you want to throw exception in specific scenarios you can do it like this
try {
restTemplate.exchange(...);
}
catch (RestClientException e) {
// implies error is related to i/o.
if (e instanceof ResourceAccessException) {
// java.net.ConnectException will be wrapped in e with message "Connection timed out".
if (e.contains(ConnectException.class)) {
// handle connection timeout excp
}
} else if (e instanceof HttpClientErrorException) {
// Handle all HTTP 4xx error codes here;
} else if (e instanceof HttpServerErrorException) {
// Handle all HTTP 5xx error codes here
}
}
for HttpClientErrorException you can get error code from excption as shown below
HttpClientErrorException clientExcp = (HttpClientErrorException) e;
HttpStatus statusCode = clientExcp.getStatusCode();
like wise, you could get error code for HttpServerErrorException.

As far as I remember RestTemplate.exchange method throws RestClientException. You have HttpStatusCodeException in your catch clause, which is only one of RestClientException subclasses.
The address you're trying to reach (http://123.433.234.12/receive) is not valid address, therefore you can't get ANY response from it (no 200s but no 500s or 400s too). Try to catch RestClientException and print its message to see what is going on. Then you can write some code to manage such situations.
Moreover if that does not work, try to go step by step and check wether ResponseEntity is null and what it has in its body. That's what I'm doing when I try to understand some method ;=)

Related

How do I use mockito to throw HttpClientErrorException.Unauthorized error

I am using mockito to mock my authenticationService.getUserInfo method.
I am having difficulty in try to mock HttpClientErrorException.Unauthorized.
I can't just new HttpClientErrorException.Unauthorized.
Is there any other way?
Implementation:
try {
result = authenticationService.getUserInfo(accessToken);
} catch (HttpClientErrorException.Unauthorized e) {
String errorMsg = "Invalid access token - " + e.getMessage();
throw new InvalidAccessTokenException(errorMsg);
}
Test case:
#Test
public void givenInvalidToken_whenGetUserInfoThrows401Response_thenThrowInvalidAccessTokenExceptionAndFail() throws ServletException, IOException {
HttpClientErrorException ex = new HttpClientErrorException(HttpStatus.UNAUTHORIZED);
exceptionRule.expect(InvalidAccessTokenException.class);
exceptionRule.expectMessage("Invalid access token - " + ex.getMessage());
Mockito.when(authenticationService.getUserInfo(anyString())).thenThrow(ex);
filter.doFilterInternal(this.request, this.response, this.mockChain);
}
Error logs from running test case:
java.lang.AssertionError:
Expected: (an instance of com.demo.security.common.exception.InvalidAccessTokenException and exception with message a string containing "Invalid access token - 401 UNAUTHORIZED")
but: an instance of com.demo.security.common.exception.InvalidAccessTokenException <org.springframework.web.client.HttpClientErrorException: 401 UNAUTHORIZED> is a org.springframework.web.client.HttpClientErrorException
Stacktrace was: org.springframework.web.client.HttpClientErrorException: 401 UNAUTHORIZED
HttpClientErrorException.Unauthorized is child exception of HttpStatusCodeException
public static final class HttpClientErrorException.Unauthorized
extends HttpClientErrorException
So when you throw HttpStatusCodeException the catch block will not executed since child exception will not catch parent exception.
So create HttpClientErrorException.Unauthorized and throw it
HttpClientErrorException http = HttpClientErrorException.Unauthorized.create(HttpStatus.UNAUTHORIZED, null, null, null, null);
I would also recommend to catch HttpStatusCodeException since UNAUTHORIZED is specific to 401 and any 400 series exceptions will not be caught by UNAUTHORIZED. You can also get status code from HttpClientErrorException and verify it as shown in my answer
try {
result = authenticationService.getUserInfo(accessToken);
} catch (HttpClientErrorException e) {
if(e.getStatusCode().equals(HttpStatus.UNAUTHORIZED))
//do something
String errorMsg = "Invalid access token - " + e.getMessage();
throw new InvalidAccessTokenException(errorMsg);
}

How to parse reponse body from REST API when response code is 4xx in java

I am trying to access REST API using OauthClient
try {
OAuthClient client = new OAuthClient(new URLConnectionClient());
OAuthResourceResponse response = client.resource(request, OAuth.HttpMethod.POST, OAuthResourceResponse.class);
} catch (Exception ex) {
ex.printStackTrace();
throw ex;
}
The api call returns a response body when I execute the call using Postman, but when I use this code above, it throws exception and I can not see the response body, in order to parse it.
Here is the exception:
org.apache.oltu.oauth2.common.exception.OAuthSystemException: java.io.IOException: Server returned HTTP response code: 409 for URL:
Is it possible to parse the response body for 4xx errors
You can build your response object in catch block and return like
} catch (Exception ex) {
return Response.status(Response.Status.BAD_REQUEST).entity(new PresenterClass(ex.getMessage())).build();
}
Using Presenter class constructor
Public PresenterClass(String errorMessage){
this.message = errorMessage;
}

Spring framework springframework.cloud.netflix.feign.FeignClient connection error handling

I am trying to handle exceptions when a POST is done via #FeignClient
What I would like to do is to catch and log if there is a connection problem, for example if a provider that I am connecting is down and cannot reachable. I tried to catch it with java.net.ConnectException
but I got this compilation error which makes sense
Error:(113, 11) java: exception java.net.ConnectException is never thrown in body of corresponding try statement
So my question is, is there any way to handle this specific exception when the feign client is not reachable, so I can log it as connection problem.
My FeignClient interface
public interface PluginFeignClient {
#RequestMapping(path = "/prepare", method = RequestMethod.POST, consumes = APPLICATION_JSON_VALUE)
Map<String, Object> createPrepare(#RequestBody CreatePluginPrepareRequest request);
}
Service that calls feign client
try {
PluginFeignClient resource = commsService.buildServicerPluginClient(servicer.getName(), PluginFeignClient.class, applicationId, originatingIpAddress);
Map<String, Object> response = resource.createPrepare(pluginRequest);
prepareResponse = new PrepareResponse(response);
} catch (WpbCommunicationException e) {
LOGGER.warn("ComId={}, PayId={}: Exception building Stripe resource", storedPayment.getCompanyId(),
storedPayment.getPaymentId(), e);
throw e;
} catch (FeignException e) {
LOGGER.warn("ComId={}, PayId={}: Got FeignException calling plugin", storedPayment.getCompanyId(),
storedPayment.getPaymentId(), e);
if (e.status() == 400) {
throw new InvalidDataException(e.getMessage());
}
throw e;
} catch (Exception e) {
LOGGER.warn("ComId={}, PayId={}: Unknown error calling plugin", storedPayment.getCompanyId(),
storedPayment.getPaymentId(), e);
throw e;
}
So the question is I would like to add another catch to the service to handle connection exceptions. Any idea about what kind of exception feign client is throwing?
Thanks
This is easy to do implementing your own errorDecoder class and creating a custom exception for the feignClient.
Here is a little example to achieve it:
Feign Error Handling
In case of error errorDecoder will be triggered before finishing the transaction and you can handle the exception the way you like.

Is there a good practice limit to amount of catches in one try block?

I'm writing a REST client which validates an incoming request, maps to object, then sends a request on to another REST producer.
In my validation I validate a number of required fields to build this request. For each failure I've created and thrown a custom exception. That is if one isn't thrown by the validation automatically (LocalDate.parse(myDate) for example, which throws DateTimeParseException()).
My question is, in the method in which I am handling these multiple exceptions, I have 6 catch blocks:
public ResponseEntity postSomething(#RequestBody final Request body) {
ResponseEntity<Response> response;
try {
response= myIngestionService.callIngestionInterface(body);
}
catch (EmptyResponseException e) {
//LOG error and return an error response with error message info
}
catch (DocumentNotValidBase64EncodingException e) {
//LOG error and return an error response with error message info
}
catch (HighLowPercentagesOutOfRangeException e) {
//LOG error and return an error response with error message info
}
catch (IdOutOfRangeException e) {
//LOG error and return an error response with error message info
}
catch (DateTimeParseException e) {
//LOG error and return an error response with error message info
}
catch (AnotherException e) {
//LOG error and return an error response with error message info
}
//return response
}
This seems maybe a little excessive to me, is it? I have a niggling feeling that at this point I should maybe be going back and rethinking my validation, but not sure.

How to handle read timeout exception in jersey client 1.8

I am using jersey 1.8
to call an external service.
Here is my code.
try{
ClientResponse response = webResource.header(HttpHeaders.AUTHORIZATION, encodedHashString).type(MediaType.APPLICATION_FORM_URLENCODED_TYPE).post(ClientResponse.class, formData);
}catch(ClientHandlerException che){
//handelling code here
{
when read timeout exception occurs it gives ClientHandlerException and underlying exception is SocketTimeoutException. But question here is I can not just say that since its ClientHandlerException it is a timeout exception because this exception can happen for other client related errors.
what can be the exact code to handle it, I need to do some handeling if its a read timeout exception.
Try something like this:
try {
ClientResponse response = webResource.header(HttpHeaders.AUTHORIZATION, encodedHashString).type(MediaType.APPLICATION_FORM_URLENCODED_TYPE).post(ClientResponse.class, formData);
} catch(ClientHandlerException ex) {
handleClientHandlerException(ex);
}
private void handleClientHandlerException(ClientHandlerException ex) throws ClientHandlerException {
if (ex.getCause() instanceof SocketTimeoutException) {
// handelling SocketTimeoutException code here
}
throw ex;
}
In handleClientHandlerException you also can try something like ExceptionUtils#getRootCause from apache commons lang if cause isn't SocketTimeoutException to get the root cause.
You can use the Throwables.getRootCause method from guava!

Categories

Resources