9

I am developing a very small test to simulate a 3 layered system so I can understand how Exceptions work. At the same time I would like to come up with a reasonable approach so I can use this design as further reference for similar operations in other applications.

I have been reading through different articles on the topic and it seems that there is a huge controversy over using checked or unchecked exceptions which is making me doubt about my final design.

I won’t go through the arguments used to criticize or support checked/unchecked exceptions because probably they are all well known but rather I will present my design looking for some advices in how to improve it and make it (as long as possible) similar to a real application.

The system is in charge to perform basic CRUD operations in a relational DB (lets say MySQL) using JDBC. I have the following: a presentation layer, a service layer and a persistence layer.

Based on this answer Handling Dao exceptions in service layer it makes sense for me not to expose specific layer implemantation and decouple the layers. So I decided to create my custom exceptions and wrap them into a Base Exception per layer so I can translate specific layer exceptions (i.e SQLException) into general layer exceptions (i.e PersistentException, BusinessException). And if later on the implementation changes I can simply wrap the new one into the base exception expected by the higher layer. So I have the following exceptions:

com.user.persistent.exceptions
    |_ PersistentException
    |_ ExistingUserException
    |_ Some more..

com.user.business.exceptions
    |_ BusinessException
    |_ somemore....

From Josh Bloch’s book Effective Java: “Use checked exceptions for conditions from which the caller can reasonably be expected to recover.” I am also not that sure but I believe a user can recover from a SQLExeption (i.e A user by mistake provides an existing ID, he can re-type the right one ) so I decided to make the previous exceptions checked exceptions. Here is an overview of how the classes look like:

Persistence Layer.

public interface UserDAO 
{
    public void create(User team) throws PersistentException;
}

//Implementation in DefaultUserDAO.java
@Override
    public void create(User team) throws PersistentException 
    {       
        try
        {
            System.out.println("Attempting to create an user - yikes the user already exists!");
            throw new SQLIntegrityConstraintViolationException();           
        }
        catch(SQLIntegrityConstraintViolationException e)
        {
            throw new ExistingUserException(e);
        }
        catch (SQLException e) 
        {
            throw new PersistentException(e);
        } 
        finally 
        {
            //close connection
        }
    }

Service Layer:

public interface UserService 
{
    void create(User user) throws BusinessException;
}

//Implementation of UserService
@Override
public void create(User user) throws BusinessException 
{
    System.out.println("Doing some business logic before persisting the user..");

    try 
    {
        userDao.create(user);
    } 
    catch (PersistentException e) 
    {
        throw new BusinessException(e);
    }

}

Presentation

    try 
    {
        userService.create(user);
    } catch (BusinessException e) 
    {   
        e.printStackTrace();
    }

Now the following points make me feel unsure about this design.

  1. I like the idea of having the compiler verifying if clients of the method catch/throw the declared exceptions when using checked exceptions. However, at the same time I think this approach leads to clutter code to handle all the exceptions. Not sure if it is because I am not making proper usage of exceptions or because checked exceptions really lead to clutter code.
  2. I also like the idea of decoupling layers by wrapping specific layer exceptions into General ones. But, I can see a lot of new classes being created for every possible exception instead of just throwing an existing java exception.
  3. I can also see that a lot the existing code on this application is devoted to handle exceptions and a small portion of it is devoted to the actual objective of the system.

These are actually my main concerns and make me wonder if this is really a good design. I would like to hear your opinions about it (and perhaps some small snippets of sample code). Can you guys give me some hints on how can I possibly improve it? In a way I can achieve decoupling between layers and avoid leaking layer specific concerns..

Community
  • 1
  • 1
Bartzilla
  • 2,768
  • 4
  • 28
  • 37
  • I had similar question in my mind.in my opinion use custom exception(like ur business exception) when you want to keep all the system failure in some auditing tables in database. In EJB/RMI days, business service consumers where outside the system meaning applet client would be running in users local browser, that time developers did not want to expose runtime exception to client. so they shipped this custom exception so that appropriate message could be displayed, now mostly all layers reside in the same runtime environment, so dont have custom exception unless u have strong reason for it. – Chetan Dec 22 '12 at 18:41

6 Answers6

4

I believe your application should not handle SQL exceptions when the development is complete. So, you should not catch exceptions like SQLException. Or if you are forced to catch them, then just rethrow RuntimeException. From my honour experience creating your own exceptions only makes sence if you develop some sort of library for someone else. And even in this case in many cases you may use existing exceptions. Try to develop without creating your exceptions. Create them only when you realize that you can't do without them.

Stepan Yakovenko
  • 8,670
  • 28
  • 113
  • 206
2

My thoughts here:
Regarding 1 - Yes, checked exceptions add "clutter code" - it's a trade-off,
and you need to think what is more important to you.
In many designs there is no a perfect solution,
and you must decide what suits you more.

Regarding BusinessException - I personally don't like it.
I would like to know at client side, when I add user, that it already exists .
I do not want to write a code that "Peals" BusinessException to get the Root cause.

And a general suggestion - Please use Generics for crud exception.
For example, don't use UserAlreadyExistsException, but use EntityAlreadyExistsException<User>

Yair Zaslavsky
  • 4,091
  • 4
  • 20
  • 27
1

@Bartzilla: I am also not great fan of wrapping and unwrapping exception objects in each layer, it really clutters the application code. I rather considers an error code and an error message approach a better way. I think there are three solutions to this issue:

1) Wrap DB layer exception in your application defined RunTimeException class. This RuntimeException should contain an errorcode field, an error message and original exception object.Since all your DAO APIs would throw only runtime exception, So it means business layer need not necessarily catch it. It will be allowed to bubble up till the point where it make sense to handle it. for e.g.

class DAOException extends RuntimeException{
 private int errorCode;
 private String errorMessage;
 private Exception originalException;

 DAOException(int errorCode, String errorMessage, Exception originalException){
    this.errorCode=errorCode;
    this.errorMessage=errorMessage;
    this.originalException=originalException;
    }

}

Now in this manner, your DAO method would be deciding the error code based on exception, e.g.:-

int Integrity_Voildation_ERROR=3;
 public void create(User team) throws DAOException
    {       
        try
        {
            System.out.println("Attempting to create an user - yikes the user already exists!");
            throw new SQLIntegrityConstraintViolationException();           
        }
        catch(SQLIntegrityConstraintViolationException e)
        {   int errorCode=Integrity_Voildation_ERROR;
            throw new DAOException(Integrity_Voildation_ERROR,"user is already found",e);
        }
}

and this exception can be caught in layer where it is supposed to be. In this scenario, each error code means a recoverable(actionable) exception. Ofcourse the entry point to application(servlet or filter or anything) must catch general Exception to catch irrecoverable exception and show the meaningful error to user.

2)Let your DAO API returns a Result kind of object which contains same information as provided in DAOException in case above.

So you have Result class:-

    Class Result implements IResult{

    private boolean isSuccess;
    private int errorCode;
     private String errorMessage;
     private Exception originalException;//this might be optional to put here.
    }


So a DAO API:
    public IResult create(User team) throws DAOException
    {      
   IResult result=new Result();
        try
        {
            System.out.println("Attempting to create an user - yikes the user already exists!");
            throw new SQLIntegrityConstraintViolationException();           
        }
        catch(SQLIntegrityConstraintViolationException e)
        {   int errorCode=Integrity_Voildation_ERROR;
            result.setSuccess(false);
        result.setErrorCode(errorCode);
        result.setErrorMessage("user is already found");    
        }
    return result;
}

In above case, constraint is each DAO API would need to return same Result Object. Ofcourse your business related Data can be populated in various subclasses of ResultClass. Note in both case 1 and 2, you can use an enum for defining all possible error codes. Error messages can be pulled from Database table etc.

3) If you want to avoid using errorCode, you can do: Instead of defining single RunTimeException class like DAOException(case1 above), you can define an exception hierarchy for each possible type of recoverable SQL exception, each is subclass to parent class DAOException.

An excellent example of same thing is done by java based spring framework DAO exception hierarchy. Please go through this.

ag112
  • 5,537
  • 2
  • 23
  • 42
  • @Bartzilla:though you accepted answer. I still wish to know which option did you choose finally-just for my curiosity? – ag112 Jan 03 '13 at 18:12
1

Based on convention over configuration concept you can design your exception handler, i think the fastest and reliable way for this purpose is using AOP, for this purpose you can handle exceptions in your aspect based on type of exceptions, you can make a decision for recovering from exception or not. for example if validation exception occurred you can return your input page path to sending client to existing page for filling data's correctly, if unrecoverable exception occurred you can return error page in your exception handler.

you can create a convention for your input and error pages for example, giving the global name for input and error pages. in this way you can make a decision to sending request to appropriate page based on exception type.

you can follow this post for Aspect Oriented Programming

sample added below

    @Aspect
    public class ExceptionHandlerAspect {

        @Around("@annotation(ExceptionHandler)")
        public Object isException(ProceedingJoinPoint proceedingJoinPoint) {
            try {
                return proceedingJoinPoint.proceed();
            } catch (Exception exception) {
                if (exception instanceof UnRecoverableException) {
                    addErrorMessage("global system error occurred");
                    return "errorPage";
                } else if (exception instanceof ValidationException) {
                    addErrorMessage("validation exception occurred");
                    return "inputPage";
                } else {
                    addErrorMessage("recoverable exception occurred");
                    return "inputPage";
                }
            }
        }
    }

@Target({METHOD})
@Retention(RUNTIME)
public @interface ExceptionHandler {
}

Presentation Layer

@ExceptionHandler
public String createUser() {
    userService.create(user);
    return "success";
}
Community
  • 1
  • 1
Ashkan
  • 320
  • 2
  • 17
1

Have a look at how spring-jdbc does it. I think that is a very good design. Spring handles checked exceptions from the driver layer and throws unchecked exceptions. It also translates different exceptions from MySQL, Postgres etc into standard spring ones.

I've switched to unchecked exceptions in all my code for the last 6 years and haven't looked back. 90% of the time you can't handle the codition. And the cases where you do, you know about it, either by design or by testing, and put the relevent catch block in.

David Roussel
  • 5,788
  • 1
  • 30
  • 35
0

You say 3 layered system - does this imply that these layers might run on different computers or in different processes? Or is it just organizing a code into a set of layers defined by specific function and everything running on a single node?

The reason for asking this - unless your layers are running in different processes - it adds no value to have CheckedExceptions. Having lots of CheckedExceptions just clutters the code and add unnecessary complexity.

Exceptions design is important and doing something like the way ag112 use has suggested above i.e using RunTimeException is clean, less code and manageable.

..just my thoughts

basav
  • 1,453
  • 10
  • 18