Try/Catch everything and rethrow Business Exceptions - java

Imagine some code:
public void doSomething(Object object){
try {
if (object == null)
throw new BusinessException("Object was null");
try {
// do logic actions
} catch (Exception e) {
throw new BusinessException("Something went wrong doing logic", e)
}
try {
// do some IO actions
} catch (Exception e) {
throw new BusinessException("Something went wrong doing IO.", e)
}
} catch(Exception e){
throw new BusinessException("Something went wrong in doSomething.", e)
}
}
The BusinessException is an extension of RuntimeException. I'm told by my manager and another senior engineer that BusinessException is the only exception that should ever get thrown and every method should be designed like the above method to ensure that. Anytime something goes wrong they want the same BusinessException thrown.
They idea is that they want to "abstract" away logical exceptions from the user and only provide "business exceptions" to the user. My manager does not want us to only catch specific exceptions, e.g. IOException They want to always catch(Exception) to make sure nothing is missed.
I don't understand this "abstraction" they are talking about. I'm pretty sure nothing is being "abstracted" away, an exception is just being encapsulated (or masked) in a new exception.
Semantics aside, I find this truly bizarre and I'm struggling to understand the value they think this verbose exception handling provides. It is not hard for me to imagine how this can make debugging more difficult. If any business exception gets thrown it immediately gets caught by another catch block and re-wrapped into a new exception, complicating the stack trace and potential debugging efforts.
It also seems like a performance issue to have so much exception instantiation.
Further, this is a spring boot application and we already have a ResponseEntityExceptionHandler
#ControllerAdvice
public class MyAppResponseEntityExceptionHandler extends ResponseEntityExceptionHandler{
#ExceptionHandler(value = { IllegalArgumentException.class })
protected ResponseEntity<Object> handleConflict(IllegalArgumentException ex, WebRequest request) {
String bodyOfResponse = "Check the arguments";
return handleExceptionInternal(ex, bodyOfResponse, new HttpHeaders(), HttpStatus.CONFLICT, request);
}
// Several more for different exception types...
}
Is this just a "to each their own" situation or is this objectively a problem?

First of all, it's never recommended to have a generic catch block that catches and instance of Throwable or Exception, unless it exists in a chain of catch blocks, for example:
public void doSomething() {
try {
// do some database stuff
} catch (SQLException e) {
throw new BusinessException("something went wrong with database", e);
}
try {
// do some IO stuff
} catch (IOException e) {
throw new BusinessException("something went wrong with IO");
}
}
Now anything other than those two exceptions shouldn't be caught, since it's not the responsibility of this particular function, function should only complain about errors that are relative to what they do.
as a caller I might do something like this:
SomethingDoer s = new SomethingDoer();
s.doSomething();
now if I'm worried that an exception might get thrown unexpectedly, it's my responsibility as a caller to handle it, so the API deligates the uncaught exception for the caller to handle, like so:
SomethingDoer s = new SomethingDoer();
try {
s.doSomething();
} catch ( BusinessException e) {
LOGGER.error(e.message) // prod logging
LOGGER.debug(e) // debug logging with stacktrace
// hypothetical error listener
errorListener.onError(e);
//handle or log, but not rethrow.
} catch (Exception e) { // cringe..
LOGGER.error("something went wrong, unexpectedly"); // prod logs
LOGGER.debug("something went wrong, unexpectedly", e); // debug logs with stacktrace
/* logged AND rethrown since up till this point all expected
exceptions should be wrapped and rethrown or logged,
so if we get here its a fatal error, and you need to interrupt the application*/
throw e;
The latter - cringe looking - catch( Exception e) block is also not recommended and the exception should be propagated up the stack to the main thread, Checked Exceptions are usually handled that way.
So language specific exceptions - internal - should be caught and wrapped in a BusinessException even before reaching the ControllerAdvice handler and this handler - since it is relatively close to the view layer of the app should only handle business specific exceptions and not internal exceptions.

Your manager and senior engineer may be considering Effective Java. From the third edition, Item 73: Throw exceptions appropriate to the abstraction.
It is disconcerting when a method throws an exception that has no apparent connection to the task that it performs. This often happens when a method propagates an exception thrown by a lower-level abstraction. Not only is it disconcerting, but it pollutes the API of the higher layer with implementation details. If the implementation of the higher layer changes in a later release, the exceptions it throws will change too, potentially breaking existing client programs.
To avoid this problem, higher layers should catch lower-level exceptions and, in their place, throw exceptions that can be explained in terms of the higher-level abstraction. This idiom is known as exception translation.
Perhaps your manager is being overzealous with this bit of advice. Effective Java goes on to caution,
While exception translation is superior to mindless propagation of exceptions from lower layers, it should not be overused.
You may be justified in pointing out this overuse to your manager, but I suspect persuasion will be difficult. You can take some solace in Item 72: Favor the use of standard exceptions. I personally prefer that advice, and tend to avoid creating custom exceptions, but certainly other developers feel differently.

It is like, the end user doesn't know what to do with exception so a generic exception will be better.
You can write diff custom exceptions for diff type of operations, like Database calls, api calls and return only one type of exception to the caller.
i.e You can define you custom exception like this.
public class BusinessException extends RuntimeException {
private final ErrorCodes errorCode;
private final Object body;
public BusinessException(String message, ErrorCodes errorCode) {
super(message);
this.errorCode = errorCode;
this.body = null;
}
public BusinessException(String message, ErrorCodes errorCode, Object body) {
super(message);
this.errorCode = errorCode;
this.body = body;
}
}
Where ErrorCodes is the enum that will be having the ErrorCodes like InternalError, EntityNotFound, Unauthorised.
Now you can use this custom exception, you will catch any exception in the application and throw this exception with proper error message and error code.
Something like this.
throw new BusinessException("Error while fetching some api data.", INTERNAL_SERVER_ERROR);
or
throw new ServiceException("User is not authorised to perform operation.", UNAUTHORIZED);

Related

How to throw an Exception inside a Try/Catch block?

I have the following Java method:
public Class createClass(Class class) {
try {
// retrieve the professor of the class and check if he exists
Professor professorFound = professorRepository.findById(class.getProfessorId());
if (professorFound != null) {
// if the professor exists, then check if he already has a class
// with the same id
List<Class> classes = professorFound.getClasses();
List<Class> classFound = classes.stream().... // loop to find the class...
// if he has, throw an exception
if(!classFound.isEmpty()) {
throw new ClassAlreadyRegisteredException();
} else {
// if he does not have, then create the class
Class class = new Class();
professorFound.getClasses().add(class);
return professorRepository.save(professorFound);
}
} else {
// if the professor does not exist, throw an exception
throw new ProfessorNotFoundException();
} catch (Exception e) {
// if there is any other error during the communication with the database,
// throw a generic IOException
throw new ClassIOException();
}
}
Basically, what I need is to throw specific Exceptions (if the professor informed in the request does not exist, or if the professor already has a class with the same id), or throw a generic IOException if there is any other error during the communication with the database.
However, in the way that I have developed, if any specific Exception is thrown, the try block will catch the exception and will throw a generic IOException.
How can I solve this problem?
I'm very interested in understanding what are the best practices in this case.
Should I catch each specific exception separately and throw them twice?
Is that a good practice?
EDIT:
This is how my ClassAlreadyRegisteredException looks like:
public class ClassAlreadyRegisteredException extends ApiException {
private static final long serialVersionUID = 1L;
public ClassAlreadyRegisteredException(String code, String message, String developerMessage, String origin, HttpStatus status) {
super(code,message,developerMessage,origin, status);
}
}
This is how my ApiException looks like:
#Data
#AllArgsConstructor
#RequiredArgsConstructor
#EqualsAndHashCode(callSuper = false)
public class ApiException extends RuntimeException{
private static final long serialVersionUID = 1L;
private String code;
private String userMessage;
private String developerMessage;
private String origin;
private HttpStatus status;
}
Thanks in advance.
Catch and re-throw.
try {
... same as before ...
} catch (ClassAlreadyRegisteredException | ProfessorNotFoundException e) {
throw e;
} catch (Exception e) {
// if there is any other error during the communication with the database,
// throw a generic IOException
throw new ClassIOException();
}
Alternatively, remember the exception to throw it later.
Exception fail = null;
try {
….
// save exception in place of existing throws
// for example:
fail = new ClassAlreadyRegisteredException();
…
} catch (Exception ex) {
...same as original...
}
if (fail != null) {
throw fail;
}
I use both techniques; the choice depends on what is simpler in any given situation. Neither is uncontestably better.
For the catch and re-throw method, you have to keep the list of caught-and-rethrown exceptions consistent with the exceptions you actually throw from within the try-clause. In larger cases, I'd avoid that problem by using an exception hierarchy, so I could catch the common base class.
For the save-and-throw method, you have to arrange control flow so that nothing significant is done after detecting the failure, since you don't have the immediate 'throw' command to exit the try-clause. Nevertheless there are cases where it is simple enough; the original example is one such.
Checked vs Unchecked Exceptions
It's totally acceptable to throw an exception in a catch block. A common use case is to take a checked Exception and throw a unchecked RuntimeException which would allow the exception bubble up to where it needs to be handled.
You'll want to use checked exceptions for use cases such as Connectivity/IO, SQL exceptions..
Handling Checked Exceptions
To answer your question, in most libraries that connect to the database, an checked IOException is thrown if there are any connectivity issues. For these cases, you can always specify this in the method signature public Class createClass() throws IOException
this specifies that any callers of createClass() has to fulfill the contract that the IOException is handled.
or
You can rethrow this as a RuntimeException
try {
...
} catch (IOException e) {
throw new RuntimeException(e); // <- send the original exception so you can preserve the exception and stacktrace.
}
This will essentially bubble up to STDOUT or whatever handler your framework specifies.
CAUTION:
However, catching an cover all Exception and throwing a more specific ClassIOException can have unintended consequences.
If you have a NullPointerException this will be captured by your catch (Exception e) block and rethrown as a ClassIOException
Doing this will corrupt the stacktrace and cause your error logs to be much more difficult to debug.
Understanding what constitutes an checked Exceptions.
Another tip is to consider what your Exception cases are.
If they are standard flow of the application, service, or business logic -- these may not be appropriate exceptions.
The ClassAlreadyRegisteredException and ProfessorNotFoundException may not be exceptional cases in your application... unless these are already specified by your professor.
Sometimes these can be thrown as RuntimeException if the situation calls for it.
Best Practices?
There are still many opinions on how exceptions are handled. So here are some rule of thumb questions I ask myself when working with exceptions
Is the stacktrace preserved? Will I be able to trace back to the root Exception
Is this common logic and represents an exceptional case that deviates from what my application provides?
If I throw this exception, is it an absolute necessity for anything calling this method to handle this exceptional logic?

How to make sure that exceptions do not lose its stack trace information in java?

Recently, I met some exception problem in java, which reminded me of the typical idiom recommended by Bruce Eckel:
Converting checked to unchecked exceptions
The real problem is when you are writing an ordinary method body, and you call another method and realize, "I have no idea what to do with this exception here, but I don’t want to swallow it or print some banal message." With chained exceptions, a new and simple solution prevents itself. You simply "wrap" a checked exception inside a RuntimeException by passing it to the RuntimeException constructor, like this:
try {
// ... to do something useful
} catch (IDontKnowWhatToDoWithThisCheckedException e) {
throw new RuntimeException(e);
}
This seems to be an ideal solution if you want to "turn off the checked exception—you don’t swallow it, and you don’t have to put it in your method’s exception specification, but because of exception chaining you don’t lose any information from the original exception.
This technique provides the option to ignore the exception and let it bubble up the call stack without being required to write try-catch clauses and/or exception specifications.
However, I found it didn't work in some cases. as seen here:
package exceptions;
// How an exception can be lost
class VeryImportantException extends Exception {
#Override
public String toString() {
return "A very important exception";
}
}
class HoHumException extends Exception {
#Override
public String toString() {
return "A trivial exception";
}
}
public class LostMessage {
void f() throws VeryImportantException {
throw new VeryImportantException();
}
void dispose() throws HoHumException {
throw new HoHumException();
}
public static void main(String[] args) {
try {
LostMessage lm = new LostMessage();
try {
lm.f();
} catch (VeryImportantException e) {
throw new RuntimeException(e);
} finally {
lm.dispose();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}/* Output:
Exception in thread "main" java.lang.RuntimeException: A trivial exception
at exceptions.LostMessage.main(LostMessage.java:36)
Caused by: A trivial exception
at exceptions.LostMessage.dispose(LostMessage.java:23)
at exceptions.LostMessage.main(LostMessage.java:33)
*///:~
As the output demonstrated, the second exception completely obliterates the first one. There is no record of the first exception in the exception stack trace, which can greatly complicate debugging in real systems. usually, it’s the first exception that you want to see in order to diagnose the problem.
Joshua Bloch recommends the try-with-resource way that a resource must implement the AutoCloseable interface, which process is somewhat complex.
So, my question is this: is there any way I can use to make sure that exception will not lose its stack trace information by Bruce Eckel's approach?
You might want to consider using try-with-resource instead of a finally block. It tends to handle this situation more like it sounds you would want the situation handled. See this article for more details.
Alternatively, you could simply eat the exception (as Andy Thomas's answer shows), or (if you want to know about both exceptions that were thrown) you could combine the exceptions into a single kind of Aggregate Exception.
The problem isn't that you're wrapping the exception. The problem is that you're replacing it with a subsequent, unrelated exception thrown from the finally block.
One easy way to avoid this is to not throw an exception from the finally block.
For example:
try {
LostMessage lm = new LostMessage();
try {
lm.f();
} catch (VeryImportantException e) {
throw new RuntimeException(e);
} finally {
try {
lm.dispose();
} catch ( HoHumException e ) {
// No-op or logging
//
// If we're exiting this try-finally because an exception
// was thrown, then don't allow this new exception to replace it.
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}

Idiom to let a specific exception bypass a broad catch block?

Often, when implementing a template method or interface method, you can only throw one specific type of exception defined by the method. But your implementation may make class to API's that throw an incompatible exception type, or many different exception types.
Naturally you need to catch them and wrap the exceptions into the type suitable for the implemented method signature. Lets assume we want to implement this interface:
public interface SomeDataGetter {
public long getSomeData() throws IOException;
}
Our implementation makes use of some other API product to implement this, and the API method we are calling may have this signature:
public long loadFromDBOrCache(Object ... params) throws SQLException, IOException, ObjectNotFoundException, RuntimeException, FridayException, NotWeekendException, NumberIs42Exception;
I made this up to demonstrate the case where you can't exactly enumerate all the possibly thrown exceptions by concrete type. Do note that IOException is a type we are allowed to throw from our implementation.
Now I can go the lazy route when implementing this and wrap anything to fit my signature:
#Override
public long getSomeData() throws IOException {
try {
return loadFromDB(...);
} catch (Exception e) {
throw new IOException(e.getMessage(), e);
}
}
This will obviously wrap any exception into an IOException (even an IOException) and it works out ok. But I'd like to not wrap IOExceptions, since I am allowed to throw those without wrapping them:
#Override
public long getSomeData() throws IOException {
try {
return loadFromDB(...);
} catch (IOException e) {
throw e;
} catch (Exception e) {
throw new IOException(e.getMessage(), e);
}
}
You can imagine this gets cumbersome quickly if there are multiple possible exception in the implementation and multiple exceptions you are allowed from the implementation. I need an extra catch for each exception I want to pass throgh.
Whats the best idiom to keep that readable (also, I'm lazy, and don't want to write all these extra catches) and still avoid unneccessary exception nesting? Or shoud I not bother and just wrap everything?
One approach would be making a method that wraps all "prohibited" exceptions in an allowed one, while returning all the allowed ones unwrapped, like this:
private static void throwIoException(Exception e)
throws IOException // <<= Add other "allowed" exceptions here
{
if (e instanceof IOException) {
throw (IOException)e;
}
... // <<= Add checks for other "allowed" exceptions here
throw new IOException(e.getMessage(), e);
}
Now you can use a single catch block, and do the wrapping as needed:
try {
return loadFromDB(...);
} catch (Exception e) {
throwIoException(e);
}
One unpleasant consequence of this is that the stack trace shows the utility method at the top of the newly created IOException, but that's not important, because the real exception is the wrapped one, not the IOException wrapper. If the exception that you caught happens to be IOException, the correct stack trace should remain in place.
I would consider the lazy route of wrapping all exceptions you get into IOExceptions (or another checked exception) to be a bad practice. Instead I would consider wrapping the exceptions in runtime exceptions, thereby bypassing the catch or specify requirement. E.g.
#Override
public long getSomeData() throws IOException {
try {
return loadFromDB(...);
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
}
The reason why this is better is that checked exceptions carry a certian meaning. If you catch for instance a ParseException in your code and rethrow that as a IOException you are lying. As a user of your code I might be able to do something about certain types of checked exceptions, but if you obfuscate the true cause of an exception it will be more difficult to debug the code when an error occurs.
In general I think you should minimize the use of checked exceptions since it litters error handling code throughout your application. Also if you are using someone else's code you have no guarantee that a RuntimeException won't be thrown anyway (unless you carefully read through it all). Therefore you have to consider that possibility anyway and handle it somewhere so your application don't crash. The virtues of unchecked exception vs checked exceptions has been discussed quite a lot elsewhere here and here for instance.

Try/Catch inside or outside functions

I have a very basic question about best practice of using try/catch.
I have a simple function (DAO) like this:
public void addVehicle(Vehicle vehicle) {
em.getTransaction().begin();
em.persist(vehicle);
em.getTransaction().commit();
}
and using DAO function inside web service:
#WebMethod(operationName = "addVehicle")
public void addVehicle(Vehicle vehicle) {
try {
vehicleDAO.addVehicle(vehicle);
System.out.print("Vehicle added");
} catch (Exception e) {
e.printStackTrace();
}
}
OR is better using try/catch inside DAO function like this:
public void addVehicle(Vehicle vehicle) {
try {
em.getTransaction().begin();
em.persist(vehicle);
em.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
}
}
There is no perfect rule for that.
Often code is clearer and less complex if exceptions are catched as early as needed, but as late as possible.
You should think who has to take an action when that Exception happens, this decides if you catch it inside the method (addVehicle) or if you throw it such that the caller has to catch it.
E.g:
public void addVehicle(Vehicle vehicle) throws SQLException{
em.getTransaction().begin();
em.persist(vehicle);
em.getTransaction().commit();
}
In this example the caller has to catch.
Further only in few situations you should catch Exception or RunTimeException, better
catch that specific Exception, like IOException instead of Exception.
Somewhere in your code you will need a "last line of defense" where it make sense to catch (Exception ex). This is needed to handle errors that should not happen.
When deciding where to handle a specific kind of exception, the best rule of thumb is to stop looking at the micro details of your code, take a step back to reason about your program's logic and consider these things:
Is the exception something that your program's current operation cannot recover from? If yes, it only makes sense to put the exception at the topmost level of that operation, to ensure that it doesn't continue.
If your program can work around that particular exception (perhaps by trying something else before giving up), take each layer of nested functions (starting from the highest) and each time ask yourself: If the exception occurs during the execution of some line of code in this function, would it make sense for this function to continue? As long as the answer is "yes", move to the deeper level. As soon the answer is "no", chances are this is the best place to put the handler for that exception.
Alternatively to the previous one, you could decide what would your program's alternate "plan of attack" be in case the exception is raised. Then, go to the line of code that would raise that exception and ask yourself: Does this function have enough context information to perform the workaround I have in mind? As long as the answer is "no", move to the caller function. As soon as the answer becomes "yes", consider putting your exception handler there.
That being said, you should only catch reasonably specialized exceptions and keep the catch(Exception ex) construct only as a last resort only at the top level and only after all the other possible catch blocks, reserving it only for kinds of exceptions you really couldn't predict at the time of writing. (I know you said this is not the point of the example, but since we're at it, I thought it should be mentioned to make this answer more complete.)
You should only catch those exceptions which you want to handle. You may include a topmost exception handler to turn any unhandled exceptions into something somewhat useful for the end user.
Instead of e.printStackTrace();, try return proper exception message.
find out more about exception handling here
Here is more discussion about exception handling.
AFAIK the best practice will be smth like that:
public void addVehicle(Vehicle vehicle) {
em.getTransaction().begin();
try {
em.persist(vehicle);
em.getTransaction().commit();
} catch (Exception e) {
if (em.getTransaction().isActive()) {
try {
em.getTransaction().rollback();
} catch (Exception e) {
// Log rollback failure or something
}
}
throw new RuntimeException(e);
}
}
Use both, the only reason is to use catch RuntimeException or even Throwable. Because this kind of exception is typically thrown by the underlying frameworks. An you should catch exactly this kind of exception if you want to make some actions, for example logging, print stack trace, etc., before you re-throw it again. If you don't do in such way you may loose the cause of exception.
#Transactional
public void addVehicle(Vehicle vehicle) {
try {
//do whatever with session
} catch (RuntimeException e) {
e.printStackTrace();
throw new Exception(e);
}
}

What is the advantage of chained exceptions

I do not understand the advantages of having a chained exception in the code.
Considering the ResourceLoader example from java world, if the programmer knows of a possibility of encountering ResourceLoadException , why not catch the same exception instead of SQLException? Else, the programmer can catch both the exceptions in the same code than having to throw a new Throwable instance?
Can anyone please provide information on the need for chained exceptions?
The article says it quite well:
Exception chaining allows you to map one exception type to another, so that a method can throw exceptions defined at the same abstraction level as the method itself, without discarding important debugging information.
That is, if you have a method that loads some object from a database, you may rather want some ResourceLoadException (closer related to the methods abstraction level) instead of a low-level SQLException even if that was the original source of the problem. However, if you simply catch the SQLException and throw a ResourceLoadException instead, you may loose important debugging information.
Thus, chaining the exceptions is a good alternative. You throw a "high-level" exception, well suited for the particular method, but chain it with the exception that caused it.
Else, the programmer can catch both the exceptions in the same code than having to throw a new Throwable instance?
I don't quite follow your reasoning here. The point is that he should not need to worry about the SQLException at this level of abstraction.
Why Chain exception?
We need to chain the exceptions to make logs readable.
Take following examples of 1. without chaining and 2. chaining, exceptions to feel the difference
Create following Exceptions
class NoLeaveGrantedException extends Exception {
public NoLeaveGrantedException(String message, Throwable cause) {
super(message, cause);
}
public NoLeaveGrantedException(String message) {
super(message);
}
}
class TeamLeadUpsetException extends Exception {
public TeamLeadUpsetException(String message, Throwable cause) {
super(message, cause);
}
public TeamLeadUpsetException(String message) {
super(message);
}
}
class ManagerUpsetException extends Exception {
public ManagerUpsetException(String message, Throwable cause) {
super(message, cause);
}
public ManagerUpsetException(String message) {
super(message);
}
}
class GirlFriendOfManagerUpsetException extends Exception {
public GirlFriendOfManagerUpsetException(String message, Throwable cause) {
super(message, cause);
}
public GirlFriendOfManagerUpsetException(String message) {
super(message);
}
}
Now use them
1. Without chaining
public class MainClass {
public static void main(String[] args) throws Exception {
getLeave();
}
static void getLeave() throws NoLeaveGrantedException {
try {
howIsTeamLead();
} catch (TeamLeadUpsetException e) {
e.printStackTrace();
throw new NoLeaveGrantedException("Leave not sanctioned.");
}
}
static void howIsTeamLead() throws TeamLeadUpsetException {
try {
howIsManager();
} catch (ManagerUpsetException e) {
e.printStackTrace();
throw new TeamLeadUpsetException(
"Team lead is not in good mood");
}
}
static void howIsManager() throws ManagerUpsetException {
try {
howIsGirlFriendOfManager();
} catch (GirlFriendOfManagerUpsetException e) {
e.printStackTrace();
throw new ManagerUpsetException("Manager is in bad mood");
}
}
static void howIsGirlFriendOfManager()
throws GirlFriendOfManagerUpsetException {
throw new GirlFriendOfManagerUpsetException(
"Girl friend of manager is in bad mood");
}
}
2. Chaining
public class MainClass {
public static void main(String[] args) throws Exception {
getLeave();
}
static void getLeave() throws NoLeaveGrantedException {
try {
howIsTeamLead();
} catch (TeamLeadUpsetException e) {
throw new NoLeaveGrantedException("Leave not sanctioned.", e);
}
}
static void howIsTeamLead() throws TeamLeadUpsetException {
try {
howIsManager();
} catch (ManagerUpsetException e) {
throw new TeamLeadUpsetException(
"Team lead is not in good mood", e);
}
}
static void howIsManager() throws ManagerUpsetException {
try {
howIsGirlFriendOfManager();
} catch (GirlFriendOfManagerUpsetException e) {
throw new ManagerUpsetException("Manager is in bad mood", e);
}
}
static void howIsGirlFriendOfManager()
throws GirlFriendOfManagerUpsetException {
throw new GirlFriendOfManagerUpsetException(
"Girl friend of manager is in bad mood");
}
}
Now compare logs
1. Without chaining
com.bskyb.svod.autoingest.GirlFriendOfManagerUpsetException: Girl friend of manager is in bad mood
at com.bskyb.svod.autoingest.MainClass.howIsGirlFriendOfManager(MainClass.java:61)
at com.bskyb.svod.autoingest.MainClass.howIsManager(MainClass.java:52)
at com.bskyb.svod.autoingest.MainClass.howIsTeamLead(MainClass.java:43)
at com.bskyb.svod.autoingest.MainClass.getLeave(MainClass.java:34)
at com.bskyb.svod.autoingest.MainClass.main(MainClass.java:29)
com.bskyb.svod.autoingest.ManagerUpsetException: Manager is in bad mood
at com.bskyb.svod.autoingest.MainClass.howIsManager(MainClass.java:55)
at com.bskyb.svod.autoingest.MainClass.howIsTeamLead(MainClass.java:43)
at com.bskyb.svod.autoingest.MainClass.getLeave(MainClass.java:34)
at com.bskyb.svod.autoingest.MainClass.main(MainClass.java:29)
com.bskyb.svod.autoingest.TeamLeadUpsetException: Team lead is not in good mood
at com.bskyb.svod.autoingest.MainClass.howIsTeamLead(MainClass.java:46)
at com.bskyb.svod.autoingest.MainClass.getLeave(MainClass.java:34)
at com.bskyb.svod.autoingest.MainClass.main(MainClass.java:29)
Exception in thread "main" com.bskyb.svod.autoingest.NoLeaveGrantedException: Leave not sanctioned.
at com.bskyb.svod.autoingest.MainClass.getLeave(MainClass.java:37)
at com.bskyb.svod.autoingest.MainClass.main(MainClass.java:29)
2. Chaining
Exception in thread "main" com.bskyb.svod.autoingest.NoLeaveGrantedException: Leave not sanctioned.
at com.bskyb.svod.autoingest.MainClass.getLeave(MainClass.java:36)
at com.bskyb.svod.autoingest.MainClass.main(MainClass.java:29)
Caused by: com.bskyb.svod.autoingest.TeamLeadUpsetException: Team lead is not in good mood
at com.bskyb.svod.autoingest.MainClass.howIsTeamLead(MainClass.java:44)
at com.bskyb.svod.autoingest.MainClass.getLeave(MainClass.java:34)
... 1 more
Caused by: com.bskyb.svod.autoingest.ManagerUpsetException: Manager is in bad mood
at com.bskyb.svod.autoingest.MainClass.howIsManager(MainClass.java:52)
at com.bskyb.svod.autoingest.MainClass.howIsTeamLead(MainClass.java:42)
... 2 more
Caused by: com.bskyb.svod.autoingest.GirlFriendOfManagerUpsetException: Girl friend of manager is in bad mood
at com.bskyb.svod.autoingest.MainClass.howIsGirlFriendOfManager(MainClass.java:58)
at com.bskyb.svod.autoingest.MainClass.howIsManager(MainClass.java:50)
... 3 more
A caller of the loadResource should not need to know the exact details of how those resources are loaded, or at the very least not care about the details of why it failed. (keep in mind it might not be you that wrote loadResources, or it might be someone else that needs to use the loadResources method).
All you should care about when calling loadResource is it might throw a ResourceLoadException. Not that implementation details fails because of a SQLException - this might change with time too, later on someone might decide to load resources from somewhere else that could fail too.
You just need to load some resources, you need to handle if it fails, and not handle potential MainframeHasCrashedException, FileNotFoundException and the dozen other reasons loading those resources might fail.
Now, when something does fail, it's handy to have the original exception that caused the failure, such as an SQLException - so someone scouring through log files or similar can figure out the cause of the error by inspecting the stacktrace
You shouldn't be tempted to just catch Exception here either, if loadResources could also throw other exceptions , e.g. an UnautorizedException, you might not want to deal with that when you're calling loadResources - you might want to propagate that exception up to other callers that can deal with an UnautorizedException(and perhaps prompt the user for some credentials). a catch(Exception e) would swallow that UnautorizedException that you really can't deal with there.
The advantage is that the caller only has to handle a ResourceLoadException instead of SQLException. That way if you later change your data storage to be in a file that accessing it might cause an IOException. You don't have to go back and change the type of Exception that your caller handles. This is useful to your caller because the caller is going to handle either exception the same way.
I think the reason from that sample is that the author wishes to create a uniform interface which isn't dependent on some specific underlying system, like SQL. Hence, he converts the exception to the more general form, leaving the actual implementation transparent to the business logic.
However, in some cases it might be desirable to propagate an error like SQLException. This will be useful in places where one needs to take different actions based on the thrown Exception.
The first benefit is encapsulation. ResourceLoader might be an interface with several implementations (for instance one loading the resources from the database, while another loads them from the file system), where the implementation to use is selected at runtime. Then the caller should be agnostic to the root cause of why loading the resource failed, but might still wish to react to resource load failures. This is particularly useful if the interface declares two different exceptions to be thrown to which the caller might wish to respond differently (for instance, a TransientResourceLoadFailureException, where a retry might suceed, and a PermanentResourceLoadFailureException, where a retry is known not to succeed).
The second benefit of exception chaining is that each exception in the chain may have a different message, which allows to include additional information for debugging. In your case, note that the ResourceLoadException's message contains the name of the resource that could not be loaded, which is not guaranteed to be included in the SQLException, but might be necessary to reproduce the problem (certain databases are not exactly known for specific error messages).
These benefits come at the cost of having to write and maintain the catch blocks. You should decide on a case by case basis whether the benefits justify the cost.
Chaining exception is for debugging purposes.When you get a general exception, you can check if there is a chained lower exception and try to understand why that lower level exception occurred.

Categories