How to catch ConnectionException in Spring WebClient? - java

I have the following error handling in RestTemplate:
try {
restTemplate.postForObject(..);
} catch (ResourceAccessException e) {
throw new CustomException("host is down");
}
Question: how can I achieve the same with spring WebClient?
try {
webClient.post()...block();
} catch (Exception e) {
//cannot check due to package private access
//if (e instanceof Exceptions.ReactiveException)
if (e.getCause() instanceof java.net.ConnectException) {
throw new CustomException("host is down");
}
}
Problem: I cannot directly catch ConnectionException because it is wrapped inside the ReactiveException. Could I do better than applying multiple instanceof checks for any real underlying exceptions?

you'd handle the error reactively, using onErrorMap with the check you're doing in the predicate (see https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Mono.html#onErrorMap-java.lang.Class-java.util.function.Function-)
Note: Didn't check whether this compiles, and you can also replace the isAssignableFrom check with instanceof, if you like.
WebClient.post().....onErrorMap(t -> t.getCause.isAssignableFrom(ConnectException.class), t -> new CustomException("host is down"));

Related

Java Exception Handling best practices

I am throwing an exception NotFoundException in my controller to check whether an Object (Building here) is existent in my Database or not and send the 404 HTTP Status like so :
try {
Building building = buildingComponent.getBuildingById(id);
if (building != null) {
return ok(buildingComponent.getBuildingById(id));
} else {
throw new NotFoundException("");
}
}
catch (Exception e) {
// handle exception
e.printStackTrace();
if (e.getClass().getCanonicalName().equals("javassist.NotFoundException")) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
} else {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
}
}
I want to know if throwing and catching the exception like i did (by comparing the canonical name of the exception) is a good exeption handling practise in java spring.
EDIT : i found the solution : it is to catch multiple times (the NotFoundException and others) like this :
catch (NotFoundException e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
}
catch (Exception e) {
e.printStackTrace();
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
}
Thank you,
No, this doesn't make a whole lot of sense in multiple ways.
You're throwing the exception just to immediately catch it. If you already know there's an error just go ahead and return an error response:
if (building != null) {
return ok(buildingComponent.getBuildingById(id));
} else {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
}
There is a built in way to catch exceptions of a specific type. You should specify exceptions being caught from most specific to least specific:
try {
// do something
} catch(NotFoundException e) {
// do some error handling
} catch(Exception e) {
// catch other exceptions
}
In this code There can be two solutions:
No need to throw the exception and handle it by identifying the
exception, You can write like this:
try {
Building building = buildingComponent.getBuildingById(id);
if (building != null) {
return ResponseEntity.ok(buildingComponent.getBuildingById(id));
} else {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
}
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage());
}
Instead of writing if else in the controller you can throw the exception from the buildingComponent itself and handle the exception later like below.
try {
return ResponseEntity.ok(buildingComponent.getBuildingById(id));
} catch (NotFoundException e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
}
To map an exception to a status code they are multiple way to do it with spring:
The simple one is to just let your exception to be propagated and add #ResponseStatus to its definition. In your case #ResponseStatus(HttpStatus.NOT_FOUD) and let ResponseStatusExceptionResolver handle it.
You can create your own HandlerExceptionResolver (more in the doc)
You can use #ExceptionHandler
a full example:
#ControllerAdvice
public class ExceptionHandling {
#ExceptionHandler
public ResponseEntity<String> handle(Exception ex) {
if (ex instanceof NotFoundException) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
} else {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
}
}
}
#Controller
public class MyController {
public ResponseEntity<String> myMethod() {
Building building = buildingComponent.getBuildingById(id);
if (building != null) {
return ok(buildingComponent.getBuildingById(id));
} else {
throw new NotFoundException("");
}
}
}
Make NotFoundException a RuntimeException to avoid throws definition.
More about #ControllerAdvice. You should really look at the documentation you will find everything.

How to re-throw error after blocking call in Java Reactor?

When I call .block() in Java Reactor if there was an error it throws ReactiveException. I need to get the source exception that is wrapped into ReactiveException and re-throw it.
This code works but it there any better way to achieve the goal?
try {
return myService.getObject(.....).block();
} catch (Exception e) {
throw e.getCause() != null ? e.getCause() : e;
}
Use Exceptions.unwrap(e)
For example:
import reactor.core.Exceptions;
...
try {
return myService.getObject(.....).block();
} catch (Exception e) {
throw Exceptions.unwrap(e);
}

How to handle different exception http types with try-catch in Java?

I am a beginner in API with Java, I am writing the RESTful APIs, and now I need to write the API Handler to handle the request from the front-end. Just noticed there are so many kinds of HTTP error when handling the request.
So I am wondering how to catch these exceptions with try-catch in Java.
I did one very basic try-catch to handle the InvalidRequestException, which refers to the exception from the client side.
#Override
public String handle(final APIGatewayProxyRequestEvent event) {
if (event.getHttpMethod().equalsIgnoreCase(HttpMethod.POST.name())) {
try{
FeatureRecord featureRecord = Jackson.fromJsonString(event.getBody(), FeatureRecord.class);
featureProcessor.createFeature(featureRecord);
return EMPTY_STRING;
} catch (Exception ex) {
throw new InvalidRequestException(ex);
}
}
Now I want to split the exception type to distinguish different HTTP exceptions, like this:
#Override
public String handle(final APIGatewayProxyRequestEvent event) {
if (event.getHttpMethod().equalsIgnoreCase(HttpMethod.POST.name())) {
try{
FeatureRecord featureRecord = Jackson.fromJsonString(event.getBody(), FeatureRecord.class);
featureProcessor.createFeature(featureRecord);
return EMPTY_STRING;
} catch (InvalidRequestException ex) {
throw new InvalidRequestException(ex);
} catch (ServiceInternalException ex) {
throw new ServiceInternalException(ex);
} ... ...
}
But I don't know how to write the catch sections.
I know there are many exception types from https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/500, but how to handle them with try-catch? Do I need to write the new Exception type?
Catching more exception types
You can catch several exception types with a single catch if you catch their common ancestor class. For example
try {
//some code
} catch (Exception ex) {
//handling the catch
}
will catch all exceptions, so please be as general as possible, but still handle the errors properly, so catching Exception might be or might not be an option for you, depending on your situation.
Ways to handle an exception
You are catching several exception types and instead of handling them or throwing them, you throw an exception of the same type. For instance there is no reason to do this:
try {
//some code
} catch (InvalidRequestException ex) {
throw new InvalidRequestException(ex);
}
instead of this:
try {
//some code
} catch (InvalidRequestException ex) {
throw ex;
}
But if your catch is only throwing the same exception, then there is no point having the catch at all. You would need to make the errors user-friendly, that is, send a response to the user explaining the problems and then throw the exception. Or, you can avoid throwing the exception at all inside the catch and log some message instead.
Implementing your own Exception
This is of course an option and could be feasible if you have some custom error types.

How to handle multiple exceptions in a java method?

I've read It isn't a best practice to handle multiple Exceptions like this:
public void myMethod() throws ExceptionA, ExceptionB, ExceptionC {
//more code here
}
And then to call myMethod():
try {
myObject.myMethod();
} catch(Exception e) {
//More code here
}
Despite Exception is the parent class of all the other exceptions, it is consider a bad practice. But, in my application I'm using java SE 6 and I need to:
Do File operations that can imply a FileNotFOundException and IOException
Marshal objects (in order to create XML files) JAXBException
Create a pdf file (using pdfbox library) COSVisitorException
Send an email using JavaMail, MessagingException
The easiest way is to add a throws statement in method declaration, but what could be the proper way to write the client method?
Is it OK to add 6 or 7 catch blocks to handle all the possible exceptions?
Generally speaking (for Java 6 and below), you should handle each exception individually...
try {
myObject.myMethod();
} catch (ExceptionA e) {
// Condition for A
} catch (ExceptionB e) {
// Condition for B
} catch (ExceptionC e) {
// Condition for C
}
This allows you to handle each exception differently based on what it is, but also means you are only handling those exceptions reported to be thrown by the method
In Java 7+ you can make use of "multi-catch" or "combined catch" (we can't find an "official" term)
try {
myObject.myMethod();
} catch (ExceptionA | ExceptionB | ExceptionC e) {
// Condition for A and B and C
}
But even then, you should be focusing exceptions into "common" use groups
try {
myObject.myMethod();
} catch (ExceptionA | ExceptionB e) {
// Condition for A and B
} catch (ExceptionC e) {
// Condition for C
}
Another option, if you control how the exceptions are defined, is to extend from a common base exception, a good example of this is the FileNotFoundException which extends from the IOException, which is thrown by FileReader and FileInputStream (as examples), this means you can handle the FileNotFoundException as a common IOException should you wish...
FileReader fr = null;
try {
fr = new FileReader(new File(...));
// Read from reader...
} catch (IOException exp) {
// Common catch block
} finally {
// Best attempt to close
try {
fr.close();
} catch (Exception exp) {
}
}
Or you could handle the FileNotFoundException as it's own condition...
FileReader fr = null;
try {
fr = new FileReader(new File(...));
// Read from reader...
} catch (FileNotFoundException exp) {
// File not found condition
} catch (IOException exp) {
// Other IO condition
} finally {
// Best attempt to close
try {
if (fr != null) {
fr.close();
}
} catch (Exception exp) {
}
}
This allows you to either group "like" exceptions together, but also provides you with the control to define more fine grained conditions should you need to...
Beware though, we the above example, if I put the IOException first, the FileNotFoundException would never be handled, when doing this, make sure that you use the lowest/tightest/finest exceptions first, as they are processed sequentially in the order you have listed
Another option (which I'm not keen on, but have seen) might be to catch a "common" ancestor and then compare the actual type, which would allow you to provide common handlers for some sub-type of the exception.
} catch (IOException exp) {
if (exp instanceof FileNotFound || exp instanceof FileSystemException) {
// Common handling
} else {
// Generic handling
}
}
This might be helpful in situations where the method only throws the ancestor type (ie IOException), but you need to provide a more fine grained resolution
But, again, I would be focused on only handling the expected "common" exceptions declared as been thrown, don't be tempered to catch Throwable for example

does instanceof work for subclassed exceptions?

java.net.ConnectException extends java.net.SocketException
If I do the following, will it cater for both exceptions? ie if I catch a "parent" exception using instanceof, does that include any subclassed exceptions?
catch (Exception e)
{
if (e instanceof java.net.SocketException)
{
System.out.println("You've caught a SocketException, OR a ConnectException");
}
}
(and for the record, yes I know catching plain Exceptions is bad, just using it for this example ;) )
Exceptions are regular classes, so instanceof works fine for them.
But you don't need such a thing. The following achieves the same result:
try {
throw new ConnectException();
} catch (SocketException e) {
System.out.println("You've caught a SocketException, OR a ConnectException");
}
Yes, it will cater for both. Because ConnectionException IS A SocketException, it also is an instance of it.
Bozho already has given the right answer. I don't know your particular usecase, but you'd rather catch different exceptions:
try {
...
}
catch (SocketException ex) {
System.out.println("You've caught a SocketException, OR a ConnectException");
}
catch (Exception ex) {
...
}
I know that it's now a good way but if you want to do custom action in a many places in code you can do something like this:
public class ImageIOExecption extends Exception {
Exception ex;
public ImageIOExecption(Exception ex) {
this.ex = ex;
doCatch();
}
private void doCatch() {
System.err.println(ex.getClass());
if (ex instanceof java.net.SocketTimeoutException) {
System.out.println("You've caught a SocketTimeoutException, OR a ConnectException");
}
if (ex instanceof java.net.SocketException) {
System.out.println("You've caught a SocketException, OR a ConnectException");
}
}
}
public BufferedImage getBufferedImage() {
try {
BufferedImage srcImage = ImageIO.read(is);
is.close();
return srcImage;
} catch (Exception ex) {
new ImageIOExecption(ex);
}
return null;
}
Yes, that is how instanceof works. For exceptions it is more common to use something like this if you care about different exceptions. It works because the JVM will work down the list of catch statements in order and execute the first one that matches.
catch(ConnectException e)
{
//got ConnectException
}
catch(SocketException e)
{
/got a SocketException
}
catch(Exception e)
{
//got some other exception
}
Or below if you dont care about the difference between Connection and Socket Exception
catch(SocketException e)
{
//got a SocketException or a subclass e.g. ConnectionException
}
catch(Exception e)
{
//got another type of exception
}

Categories