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.
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..
CRUD Meaning: CRUD is an acronym that comes from the world of computer programming and refers to the four functions that are considered necessary to implement a persistent storage application: create, read, update and delete.
First, we need to set up the capability of throwing exceptions on core banking service errors. Open core banking service and follow the steps. Create a common exception class where we going to extend RuntimeException. After that, we can create custom runtime exceptions to use with this API.
CrudRepository does not provide any method for pagination and sorting. JpaRepository extends PagingAndSortingRepository. It provides all the methods for implementing the pagination.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With