Java Exception Handling best practices - java

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.

Related

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 catch ConnectionException in Spring WebClient?

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"));

Alternatives to throw an exception to minimize performance hit

I’m trying to optimize a java application and there are try/catch blocks in which the catch throws an exception:
try {
//call a web service
} catch (Exception subclass){
throws someOtherExceptionSubclass();
}
Apparently this is a big performance hit so I thought of returning null. So where should the null be after the catch block?
try {
// call a web service
} catch (Exception subclass){
//Print some exception related message
}
if ( webService.call() == "unsuccessful" ) {
return null;
} else {
return "Success";
}
What is the right place to put return null? Is there any other housekeeping to be done?
Probably you can just do this instead of multiple return statements
boolean isSuccess = true;
try {
call a web service
} catch (exceptions subclass) {
//Print some exception related message
isSuccess = false
}
return isSuccess;

rethrow java exception with new message, preserving the exception type if it is in the method declaration list

I am trying to create a helper method that will eliminate the need of having code like this:
void foo() throws ExceptionA, ExceptionB, DefaultException {
try {
doSomething(); // that throws ExceptionA, ExceptionB or others
} catch (Exception e) {
if (e instanceof ExceptionA)
throw new ExceptionA("extra message", e);
if (e instanceof ExceptionB)
throw new ExceptionB("extra message", e);
throw new DefaultException("extra message", e);
}
}
The problem is that I need to maintain the throws list in the function declaration and in the body of the function at the same time. I am looking how to avoid that and to make changing the throws list sufficient and my code to looks like:
void foo() throws ExceptionA, ExceptionB, DefaultException {
try {
doSomething(); // that throws ExceptionA, ExceptionB or others
} catch (Exception e) {
rethrow(DefaultException.class, "extra message", e);
}
}
Where rethrow method will be smart enough to recognize the throws list from the method declaration.
This way when I change the list of type that my method propagates in the throws list I to not need to change the body.
The following is a function that could solve the problem. The problem is because it does not know what type of exception it will throw its throws declaration has to say Exception, but if it does this, the method that is going to use it will need to specify it as well, and the whole idea of using the throws list goes to hell.
Any suggestions how this could be solved?
#SuppressWarnings("unchecked")
public static void rethrow(Class<?> defaultException, String message, Exception e) throws Exception
{
final StackTraceElement[] ste = Thread.currentThread().getStackTrace();
final StackTraceElement element = ste[ste.length - 1 - 1];
Method method = null;
try {
method = getMethod(element);
} catch (ClassNotFoundException ignore) {
// ignore the Class not found exception - just make sure the method is null
method = null;
}
boolean preserveType = true;
if (method != null) {
// if we obtained the method successfully - preserve the type
// only if it is in the list of the thrown exceptions
preserveType = false;
final Class<?> exceptions[] = method.getExceptionTypes();
for (Class<?> cls : exceptions) {
if (cls.isInstance(e)) {
preserveType = true;
break;
}
}
}
if (preserveType)
{
// it is throws exception - preserve the type
Constructor<Exception> constructor;
Exception newEx = null;
try {
constructor = ((Constructor<Exception>) e.getClass().getConstructor());
newEx = constructor.newInstance(message, e);
} catch (Exception ignore) {
// ignore this exception we prefer to throw the original
newEx = null;
}
if (newEx != null)
throw newEx;
}
// if we get here this means we do not want, or we cannot preserve the type
// just rethrow it with the default type
Constructor<Exception> constructor;
Exception newEx = null;
if (defaultException != null) {
try {
constructor = (Constructor<Exception>) defaultException.getConstructor();
newEx = constructor.newInstance(message, e);
} catch (Exception ignore) {
// ignore this exception we prefer to throw the original
newEx = null;
}
if (newEx != null)
throw newEx;
}
// if we get here we were unable to construct the default exception
// there lets log the message that we are going to lose and rethrow
// the original exception
log.warn("this message was not propagated as part of the exception: \"" + message + "\"");
throw e;
}
Update 1:
I can use RuntimeException to avoid the need of throws declaration, but in this case I am losing the type of the exception which is one of the most important points.
Ideas how I can resolve this?
I'm guessing that code where you're doing real work (ie. the part where you're not tinkering with exceptions) looks like this.
public void doSomeWork( ... ) throws ExceptionA, ExceptionB, DefaultException
{
try
{
// some code that could throw ExceptionA
...
// some code that could throw OtherExceptionA
...
// some code that could throw ExceptionB
...
// some code that could throw OtherExceptionB
}
catch (Exception e)
{
if( e instanceof ExceptionA )
{
throw new ExceptionA("extra message", e);
}
if( e instanceof ExceptionB )
{
throw new ExceptionB("extra message", e);
}
throw new DefaultException("extra message", e);
}
}
There are two better approaches
First Approach
public void doSomeWork( ... ) throws ExceptionA, ExceptionB, DefaultException
{
// some code that could throw ExceptionA
...
try
{
// some code that could throw OtherExceptionA
...
}
catch (Exception e)
{
throw new DefaultException("extra message", e);
}
// some code that could throw ExceptionB
...
try
{
// some code that could throw OtherExceptionB
}
catch (Exception e)
{
throw new DefaultException("extra message", e);
}
}
Second Approach
public void doSomeWork( ... ) throws ExceptionA, ExceptionB, DefaultException
{
try
{
// some code that could throw ExceptionA
...
// some code that could throw OtherExceptionA
...
// some code that could throw ExceptionB
...
// some code that could throw OtherExceptionB
}
catch (OtherExceptionA | OtherExceptionB e)
{
throw new DefaultException("extra message", e);
}
}
The first approach is good if you want to continue execution at all costs and catch and wrap RuntimeExceptions if you run into them. Generally you don't want to do this, and it's better to let them propagate up, as you probably can't handle them.
The second approach is generally the best. Here you're explicitly pointing out which exceptions you can handle, and dealing with them by wrapping them. Unexpected RuntimeExceptions propagate up, as they should unless you have some way of dealing with them.
Just a general comment: playing with StackTraceElements isn't considered to be a great idea. You may end up getting an empty array from Thread.currentThread().getStackTrace() (although you most likely will not if using a modern Oracle JVM), and the depth of the calling method isn't always length-2, it may be length-1 particularly in older versions of the Oracle JVM.
You can read more about this problem in this question.
To elaborate on what )some) people are telling you, this is MyFunctionFailedException, ofcourse it should be named something more sensible:
public class MyFunctionFailedException extends Exception {
public MyFunctionFailedException(String message, Throwable cause) {
super(message, cause);
}
}
Then your catch block becomes something like this.
try {
...
} catch (Exception e) {
throw new MyFunctionFailedException("extra message", e);
}
If you really want to rethrow a lower level exception, you should use multiple catch blocks. Be aware tho' that not all types of Exceptions necessarily has a constructor that let's you add a cause. And you really should think about why it makes sense for your method to let for instance an uncaught SQLException bubble up the call stack.

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