I want to handle a set of exceptions in one of the class which is annotated using #Named.
I am using AKKA actors for concurrency. Also using Hibernate.
In my Akka actor class, I am invoking the hibernate methods for insert operations.
I want to know how to handle exceptions in all the actor classes globally. I can do that using #ExceptionHandler and #ControllerAdvice. But I believe that it works only in the #Controller layer.
Sample code is given below:
#Named("SaveDepartmentService")
public class SaveDepartmentService extends BaseCommonService {
#Autowired
IDepartmentRepository departmentRepository;
#Override
public PartialFunction<Object, BoxedUnit> receive(){
return ReceiveBuilder
.match(Department.class, c->createOrUpdateDepartment(c))
.build()
.orElse(matchAny());
}
private void createOrUpdateDepartment(Department dept){
// try{
departmentRepository.insertOrUpdate(dept);
// }catch (ConstraintViolationException e){
// System.out.println("-------------------------------");
// e.printStackTrace();
// wrap the exception and send as
// sender().tell("Constarint_violation",self());
//}
sender().tell(dept, self());
} }
I want to handle ConstraintViolationException across my actors and respond with a message (eg: sender().tell("CONSTRAINT_VIOLATION", self());).
I can do the same thing by handling it in catch block, but i need to duplicate it in all actor classes.
Is there any way to handle it like #ControllerAdvice?
You could use the default exception handler.
By setting the default uncaught exception handler, an application can change the way in which uncaught exceptions are handled (such as logging to a specific device, or file) for those threads that would already accept whatever "default" behavior the system provided.
But it makes no difference between CDI-Beans and Non-CDI-Beans (By the way: I use it to automatically increase the level of logging of all classes in the Stacktraces)
Related
I have a global exception handler to share across REST #Controllers. For this I use a #ControllerAdvice with some #ExceptionHandler methods. This works fine. Now, if I add an #ExceptionHandler in a particular Rest Controller then that new handler takes precedence over the global exception handler and the global one is just never called.
What I need is actually to have both called. The order doesn't matter. The point is that there is some global, controller-agnostic error handling code and also some controller-specific error handling and I need both to execute. Is this possible? e.g. Can I somehow in the controller-specific handler (which is called first) mark the exception handling as not handled so the next handler in line is invoked?
I know I could inject the #ControllerAdvice in the #Controller and invoke the global handler from the specific one myself, but I rather keep the controller decoupled from the global exception handler
I don't think you can do this with out-of-the-box Spring. If you look under the hood at this method ExceptionHandlerExceptionResolver#doResolveHandlerMethodException, you can see that at first Spring looking for single method that will handle occurred exception:
...
ServletInvocableHandlerMethod exceptionHandlerMethod = getExceptionHandlerMethod(handlerMethod, exception);
if (exceptionHandlerMethod == null) {
return null;
}
...
You can also look at the implementation of getExceptionHandlerMethod method. First its trying to find appropriate handler within you controller methods, if nothing found - then within controller advisors.
After that it invokes it:
try {
if (logger.isDebugEnabled()) {
logger.debug("Invoking #ExceptionHandler method: " + exceptionHandlerMethod);
}
exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, exception, handlerMethod);
}
catch (Exception invocationEx) {
if (logger.isErrorEnabled()) {
logger.error("Failed to invoke #ExceptionHandler method: " + exceptionHandlerMethod, invocationEx);
}
return null;
}
You should also note that Spring swallows any exception that might occur during original exception handling, so you can't even throw new exception from your first handler or rethrow original exception so it can be catched somewhere else (You can actually, but this is pointless).
So, if you really want to do this - I guess the only way is to write you own ExceptionHandlerExceptionResolver (maybe extend Springs ExceptionHandlerExceptionResolver) and modify doResolveHandlerMethodException method, so it looks for multiply exceptionHandlerMethod (one within controllers and one within advisors) and invokes it in a chain. This might be tricky :)
Also, you can look at this Jira ticket.
Hope it helps.
I have heard that it is possible to log (or do something else) Exceptions with Spring in my web-App, so I don't have to manually insert in every "catch(){}" block the Log-function.
Does anyone have experience with Spring-overall-logging? I just want to get informed when an error appears
ExceptionHandler is the central point for handling unexpected Exceptions that are thrown during the Faces lifecycle. The ExceptionHandler must not be notified of any Exceptions that occur during application startup or shutdown.
See the specification prose document for the requirements for the default implementation. Exceptions may be passed to the ExceptionHandler in one of two ways:
1.)By ensuring that Exceptions are not caught, or are caught and re-thrown.
This approach allows the ExceptionHandler facility specified in section JSF.6.2 to operate on the Exception.
2.)By using the system event facility to publish an ExceptionQueuedEvent that wraps the Exception.
This approach requires manually publishing the ExceptionQueuedEvent, but allows more information about the Exception to be stored in the event. The following code is an example of how to do this.
Global Exception Handler – Exception Handling is a cross-cutting concern, it should be done for all the pointcuts in our application. We have already looked into Spring AOP and that’s why Spring provides #ControllerAdvice annotation that we can use with any class to define our global exception handler.
The handler methods in Global Controller Advice is same as Controller based exception handler methods and used when controller class is not able to handle the exception.
Sample Code
#ExceptionHandler(Exception.class)
public ModelAndView getExceptionPage(Exception e, HttpServletRequest request) {
request.setAttribute("errorMessageObject", e.toString());
return model;
}
** Here we can catch the base exception class Exception.class or any other exception class. Also we can throw and catch our own custom defines exception class.
So in my Service layer I have some logic that does some stuff. Sometimes it has to check to see if something is possible before it does it OR it just has to get some OK from the front end ("Are you sure you want to do this?" kind of stuff). The front end, of course, sends a transaction to the screen to get the info.
In the past I have used RuntimeExceptions for this. I will throw a
new MessageException("are.you.sure");
and then the controller level will do a
try{
theService.doSomething();
}catch(MessageException me) {
model.addAttribute(me.getMessageKey());
result.addError(new ObjectError());
}
In another application I made a PostOffice object and would put letters and such in it for messages. It was quite elaborate and very nice, but my new app is much smaller and I don't want all that.
So I am looking for some best practices. How do you guys send messages from the service layer to the front end? And keep in mind, I am NOT talking about Exceptions! I am just talking about messages from the service layer.
One beautiful thing about Spring MVC is the Exception handling. Since the DispatcherServlet has a try-catch(Exception) wrapping the handler method (ie. your controller method), it can catch all exceptions thrown and handle them with #ExceptionHandler methods or some other construct (there are alternatives).
What I've started doing is making my Service methods only throw RuntimeException instances (works well with #Transactional) and define all my #ExceptionHandler methods in a #ControllerAdvice annotated class. Something like:
#ControllerAdvice
public class ControllerHandler {
private static final Logger logger = LoggerFactory.getLogger(ControllerHandler.class);
#ExceptionHandler(value = AuthenticationException.class)
public String handleAuthenticationException(AuthenticationException e) {
if (logger.isInfoEnabled()) {
logger.info("An AuthenticationException occurred: {}", e.getMessage());
}
return "redirect:/";
}
...more
}
#ExceptionHandler annotated methods have a few rules, but are very customizable. You can see all possibilities in the javadoc here. You should also take a look at ResponseStatus.
Personally, I rarely throw checked exceptions from my service layer. The only one that often appears is IOException (parsing JSON, opening files) and even that I like to wrap in a RuntimeException, because it's not like I can do anything special about it at that level.
I'm currently working with MyBatis-Spring integration framework and that's what I read from docs:
Rather than code data access objects (DAOs) manually using SqlSessionDaoSupport or SqlSessionTemplate,
Mybatis-Spring provides a proxy factory: MapperFactoryBean. This class lets you inject data mapper interfaces
directly into your service beans. When using mappers you simply call them as you have always called your
DAOs, but you won't need to code any DAO implementation because MyBatis-Spring will create a proxy for
you.
That's a very nice feature... but what about exception handling? Where should I translate SQL errors? In my service layer? But wouldn't it violate service-DAO patterns?
Example:
public final class AccountServiceImpl implements AccountService {
(...)
private AccountMapper accountMapper;
(...)
#Override
public void addAccount(Account account) throws AccountServiceException {
//Validating, processing, setting timestamps etc.
(...)
//Persistence:
int rowsAffected;
try {
rowsAffected = accountMapper.insertAccount(account);
} catch (Exception e) {
String msg = e.getMessage();
if (msg.contains("accounts_pkey"))
throw new AccountServiceException("Username already exists!");
if (msg.contains("accounts_email_key"))
throw new AccountServiceException("E-mail already exists!");
throw new AccountServiceException(APP_ERROR);
}
LOG.debug("Rows affected: '{}'", rowsAffected);
if (rowsAffected != 1)
throw new AccountServiceException(APP_ERROR);
}
Is it OK to translate exceptions in service layer?
How should it be done?
Thanks in advance for you advice.
Having recently used mybatis-spring for a project I came across the same stumbling block. I also didn't want to litter my service class with DAO exception handling, particularly since some methods in my service layer required read-only access to a lot of different tables.
The solution I arrived at was to catch the exceptions in the service layer but create your own exception type that takes the caught exception as a parameter. This can then filter out what kind of error message should be contained when the exception is actually constructed and remove the need for string matching (in the service layer at least).
You are close to that there, except the AccountServiceException would have a constructor that took the Exception e as a parameter. I also chose to try and do all my data access as early as possible and wrap it all in a single try/catch. Since the MapperFactoryBean always translates thrown exceptions in to Spring DataAccessExceptions you don't have to worry about catching other kinds of exceptions when doing data access.
I hesitate to consider this an answer as such - more of a sharing of experience given I came across that and hesitated as well.
Translating low level DataAccessExceptions thrown by MyBatis to application-defined ones in service layer is a standard practice.
It's usually connected to transaction handling as you can't handle the transaction spanning multiple DAOs in DA layer.
So yes it's OK and even recommended.
Normally I log the exceptions thrown by DAO in error log and rethrow something defined by application.
I was hoping to implement a single "ExceptionController" to handle exceptions that are thrown in execution of my other controllers' methods. I hadn't specified any HandlerExceptionResolver in my application context so according to the API documentation the AnnotationMethodHandlerExceptionResolver should be started. I verified it as such in the source. So why doesn't the following work?
#Controller
public class ExceptionController {
#ExceptionHandler(NullPointerException.class)
public ModelAndView handleNullPointerException(NullPointerException ex) {
// Do some stuff
log.error(logging stuff)
return myModelAndView;
}
}
#Controller
public class AnotherController {
#RequestMapping(value="/nullpointerpath")
public String throwNullPointer() {
throw new NullPointerException();
}
}
I see in the debug logs that the three default exception handlers are asked for handling of the exception, but nothing is done and I see "DispatcherServlet - Could not complete request". Followed by the user being displayed the stacktrace and a 500 Internal error.
Make sure your Exception handler is returning a view that exists/maps to a handler.
You should write your exceptionhandler to the same class with which you want to handle, like the following.
#Controller
public class AnotherController {
#ExceptionHandler(NullPointerException.class)
public ModelAndView handleNullPointerException(NullPointerException ex) {
// Do some stuff.
log.error(logging stuff)
return myModelAndView;
}
#RequestMapping(value="/nullpointerpath")
public String throwNullPointer() {
throw new NullPointerException();
}
}
I don't think this is a good design. Controllers in Spring handle HTTP requests and map to URLs. I don't think "exception" fits into either bin. It feels like a misuse of Spring to me.
An exception is not an HTTP request. You don't map an exception to a URL. Therefore I'd conclude that controllers aren't intended to be treated as exception handlers.
Controllers are a part of the Spring API, but your design isn't using them as intended, so that's why it's not working. Re-think your design.