Reputation: 81
I'm working on an application where the process goes on like this
UI --> backend process --> result to UI.
In my Java code, I have handled my exceptions using try-catch, But in the code I have so many repeated exceptions that may throw same exceptions in different classes, which reduces the readability and code reuse.
So, I am planning to do a exception handling strategy so that instead of throwing the same exception in different classes, I need to organize the exception and reuse the exception codes.
Could anyone suggest me best exception handling technique to do this?
Upvotes: 4
Views: 3101
Reputation: 1640
Instead of writing more comments (deleted excess), I'll put some of my thoughts here + one kind of generic solution I came up with.
http://docs.oracle.com/javaee/6/tutorial/doc/bnbpj.html
This puts this matter in simple context. When people are not used to exceptions (like script/functional programmers) they rant about using only RuntimeExceptions ... which takes you in polluting the frontend with un-managed errors bubling on UI. (I do not find that very convenient if you consider the program code in long run ... maintainability)
http://www.onjava.com/pub/a/onjava/2003/11/19/exceptions.html
If the client can take some alternate action to recover from the exception, make it a checked exception. If the client cannot do anything useful, then make the exception unchecked. By useful, I mean taking steps to recover from the exception and not just logging the exception.
(There are posts about logging patterns with Exceptions, but I am not going there in this as it trails off)
It is hard to detect unchecked exceptions and they easily get pass your "close to source" catching. (When they are unchecked, they will be invisible for the client code and will slip through).
I am challenged with this issue with some legacy code throwing lots of unchecked exceptions that crash the UI now. (because of unreliable services)
Probably "everyone" has their own opinion how to do things correctly, but I am trying to have a generic pattern for catching the errors (unchecked Exceptions) close to UI and presenting them in nice error popups (JSF by the way) instead of directing the user to "error.xhtml" page (introduced in web.xml).
// For the above scenario I came up with this solution.
It even seems to work pretty well.
Interceptor binding annotation
@Inherited
@InterceptorBinding
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface InterceptEJBExceptions {}
The interceptor
@Interceptor
@InterceptEJBExceptions
public class EjbExceptionInterceptor {
@AroundInvoke
public Object interceptBubblingExceptions(final InvocationContext context) throws Exception {
try {
return context.proceed();
} catch (MySpecificEJBException msejbe) {
Object[] args = { msejbe.getErrorCode(), msejbe.getMethodSignature(), msejbe.getParameters()};
// This would create a FacesMessage in JSF
addErrorMessageToFacesContext(null, summary_template, details_template, args);
} catch (EJBException ejbe) {
super.addErrorMessageToFacesContext(null, "Unspecified EJBException", ejbe.getMessage());
}
// "Pure" RuntimeExceptions will fall through and will be shown on 'error-page' specified in web.xml
return null;
}
}
beans.xml
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
<interceptors>
<class>xxx.xxx.xxx.exception.interceptor.EjbExceptionInterceptor</class>
</interceptors>
</beans>
Usage in java classes
@RequestScoped // Class must be in EE context
// @InterceptEJBExceptions // Have the annotation at class level to intercept all method calls in this class
public class MyBB {
@InterceptEJBExceptions // Only intercept when this method gets called
public String myEjbExceptionThrowingActionListener(Object obj) {
// Some code that may throw an EJBException
}
}
MySpecificEJBException Would be an Exception class extending EJBException. Construct the class as you like to transport usefull information for later logging and for showing a clean error messages on a screen instead of vomitting the exception on screen with or without error-page defined in web.xml (which you should also have as a fallback).
Do not forget to include the original Exception in the class!
Create more your own Exceptions extending EJBException as you need and throw them as you like (as RuntimeExceptions they are unchecked). Then just add the catch block in the interceptor and do the logging and/or error message displaying specific for that case.
In general:
Use checked Exceptions where you can to react for the error.
In Java 7 you can use the following syntax to group Exceptions that can be handled similarly.
try {...} catch (SomeException | OtherException e) {...}
If you have lots of checked Exceptions, you can/should maybe group them in categories (extend some more generic Exception of yours). You can then catch based on that grouping exception (in addition to/instead of having grouping catch-clauses).
I could not find any actual solution for error handling (as pattern), but a lots of debate what is right and what is wrong. We have 2 types of Throwables, so why not use them both constructively?
Instead of continuing this debate, I am hoping this will be a real solution and do the trick.
I'd appreciate all constructive comments and improvement suggestions.
Upvotes: 0
Reputation: 92210
Edit: Original answer moved here in your other question: https://stackoverflow.com/a/16172074/82609
To keep my answer in the question scope, here are the interesting parts:
Avoid exception codes
The exception type should be sufficient for flow control decisions. Parsing exceptions or flow control will only create useless code. Add more exception types, as much as you have exception codes.
Item 39: Use exceptions only for exceptional conditions (Jochua Bloch's Effective Java chapter):
Item 39: Use exceptions only for exceptional conditions. That is, do not use exceptions for control flow, such as catching NoSuchElementException when calling Iterator.next() instead of first checking Iterator.hasNext().
In functional languages we tend to only use exceptions for really exceptional conditions. An exceptional condition is something like "can't connect to the database" and not something like "the user did not provide the article quantity he wants in the input text". This is not exceptional, this is a business error.
The Java language doesn't help that much but ideally you may return that business error, as an output of the function (for exemple, an instance of EnumAddBasketError) instead of creation an AddProductToBasketWithoutQuantityException. In practice people will tend to raise an exception, breaking the normal control flow, and slowing down the application (exceptions have a cost).
Avoid checked exceptions
Read my other answer here: https://stackoverflow.com/a/16172074/82609 Checked exceptions are for recoverable failures (Sun recommendations). Unchecked exceptions are more easy to deal with for unrecoverable failures.
In the end what I mean is that you probably don't need all these exceptions, because most of them are probably unrecoverable, or may not be exceptional.
Upvotes: -2
Reputation: 5585
Always handle Unchecked Exceptions as close to their source as possible but avoid creating them, they are an inherently unsafe programming idiom of last resort; when there is no possibility that the program can recover.
When implementing application, code defensively buy always using checked exceptions when coding to manage exceptional work flows; such as when your code fails to honour its interface "Contract".
An application should not crash with an unchecked exception because it cannot reach a third party credit score system. Disable that option and continue allowing Cash Customers to be created.
Generalise exception handling but specialise their creation. e.g.
CustomerNotFound extends CustomerException
CreditCustomerNotFound extends CustomerException
CashCustomerNotFound extends CutomerException
{
aCustomer = customerList.find( ... )
} catch CustomerNotFound() {
logger.warn( ... )
throw CustomerException(CustomerNotFound)
}
InvoiceAddressException extends InvoiceException
Do specific handling as close to the source as possible, log details and clean up as much as possible. Propagate only
Do general handling and reporting as close to the user interface as is realistic.
Upvotes: 3
Reputation: 2049
I would like to show a design oriented approach for this,
firstly "Martin Spamer" is right as we need to catch only Checked exception....but in very granular level...e.g. InvalidCredentialException and AuthorizationException should not be thrown/catched as LoginException, because, suppose you throw it as Single type exception and then you are asked to handle these types in different way in future, then??
secondly, there tiers are UI ----> front tier ----> service tier -----> DAO tier
The Logic should be,
(i) front tier will recieve request from UI and handle front end based validations/exceptions (e.g. MissingUserNameException while login). If everything is OK, then forwards the request to Service layer
(ii) service will validate bussiness logics and if valid then it will process the request. If not it will throw exception with proper message to frontend tier
(iii) but each of service level exception messages may not be appropriate for user display. so front tier's responsibility should be converting the business exception in to client-readable exception
This approach will have another added advantage. Suppose, tomrw a requirement comes up where you need to expose some business methods as Web-service...so your services will be exposed anyhow. Now if you put your entire exception handling (i.e. converting exception into proper message) logic in frontend tier and service tier is completely unaware of them...then it will be a mess where you need to again refactor your service tier code (and also front tier). Even some times later, another situation may come up that your front tier technology becomes obsolete and you have to recode your entire exception handling logic in new technology.
So the bottom line is, service tier should know+handle all the business validation exceptions with a proper message. After decorating the exception with proper message, it will hand it over to client layer where from the service was invoked. Now it is client tier's responsibility, to show the message and decorate it again with some other message if required. This way, you can keep all of the tiers independant.
Upvotes: 1
Reputation: 17940
Since you have a GUI which is going to be used by a client, the client would need to know if an exception occurred, so the best place to handle the exceptions would be your upper most layer(the one that communicate with the GUI).
You could also catch the exceptions where it was thrown, log it and then throw it again.
That means all other, lower layers will just throw the exception.
You can create some custom exceptions and use them instead of the regular ones (i.e. catch SqlException and throw MyDBException with more details like exception code , query string etc.)
EDIT
I would also consider deviding the exceptions to 2 categories: Logical and Functional.
Then you can decide on a strategy for handling each type. Logical exceptions would return specific data to the user (invalid username/pwd) and Functinal exceptions would return a more generic message like: There was a problem, please contact support.
Upvotes: 2