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.
- 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.
- 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.
- 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..