Should service layer catch all dao exceptions and wrap them as service exceptions

daodesign-patternsexception handlingspring

I have three layer Spring web app: dao, service and controllers. A controller never calls directly the dao, it does it through the service layer. Right now, most of the time if there is dao exception (runtime) that is not handled, it'll be caught by a JSP showing an error message to the end user.
Should service layer catch all dao exceptions and wrap them as service exceptions?

try {
   daoInstance.someDaoMethod();
} catch(DataAccessException dae) {
   throw new ServiceException("message", dae);
}

Let's suppose ServiceException is runtime as well and it's not handled neither. Is there any difference to just throw the DataAccessException instead of the ServiceException?
I just thought that the presentation layer should not know about data access exception. But I don't see the point of catching unrecoverable exceptions just to wrap them.

Best Answer

I think an important factor is who your service clients are.

If your service layer is just an architectural boundary between layers in your own project, and the service client is within the same trust realm, then it is ok to relax things, and let unchecked exceptions bubble out to the controller layer, or the service client.

However, for public facing code; service that are consumed by a third party or customer, I think it is cleaner to wrap any unchecked exceptions with a service oriented exception, primarily for security concerns, secondly for loose coupling, and clean abstraction.

A data layer exception should never, directly make it all the way to an end user of a web application. It potentially contains internal information about your schema, your queries, line number information, variable or function names, etc. End user exceptions can be sanitized in a secure setting.

An external service client isn't concerned with your implementation detail, and can't handle unchecked exceptions anyway, as they are bug or environmental issues. In secure applications, database errors are simply not secure enough to propagate, OracleException - ORA-01234 - ... which might be the 3rd table that was inserted. The client should be allowed to deal with any checked/expected exceptions that it can handle, and treat everything else as a potential bug report. Your service contract should be an atomic, consistent, transactional abstraction. If it can't do anything about the exception, then the only useful thing left is to give you a bug report. You already have the ability to log the exception, so why burden your end user with the details? Your app can be monitored, so you already know about the unchecked exceptions before the users report them.

It is never ok to eat exceptions, nor am I a fan of checked exceptions, but I prefer to have a plan that is appropriate for the nature of the overall product.