I am having some problems getting my @AfterThrowing advice to run when calling the class (that throws the exception) from inside a try/catch block. If I dont catch the exception in the calling class, the advice runs like it should (maybe because the advice is applied to the controller only?). I am using a "two layer structure" (Controller->Service) and Spring 3.1 + AspectJ to test this.
My app-context.xml has amongst other tags:
Code:<bean id="airbrakeExceptionLogging" class="demo.aspects.AirbrakeExceptionLoggingAspect" /> <aop:aspectj-autoproxy proxy-target-class="true"/>
My code looks like this (I have left out some parts of the files and changed the package name to "protect the innocent" whilst trying to keep everything that I believe could effects this issue):
My @Aspect:
Code:package demo.aspects; import org.apache.log4j.Logger; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; @Aspect public class AirbrakeExceptionLoggingAspect { public static Logger logger = Logger.getLogger(AirbrakeExceptionLoggingAspect.class); @Pointcut("within(demo..*)") public void anyPublicMethod() {} @AfterThrowing(pointcut="anyPublicMethod()", throwing="ex") public void logException(JoinPoint jp, Throwable ex) throws Throwable { logger.warn("Exception occured: " + ex.getClass().getName() + ": " + ex.getMessage()); } }
My controller, this is the calling class:
And my Service class, this is the class where I was hoping the advice would execute:Code:package demo.controller; import demo.service.AuthTokenService; import demo.ServiceManagerSingleton; import demo.view.JSONView; import org.jdom.Document; import org.jdom.Element; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; @Controller @RequestMapping(value="/token") public class TokenController { private AuthTokenService authTokenService = null; public TokenController() throws Exception { authTokenService = ServiceManagerSingleton.getAuthTokenServiceInstance(); } @RequestMapping(value="/exception/{throwException}") public ModelAndView causeException(@PathVariable boolean throwException) throws Exception { ModelAndView result = new ModelAndView(new JSONView()); try { authTokenService.causeExceptionInService(throwException); result.getModelMap().put("json", "Everything went better then expected"); } catch(Exception e) { result.getModelMap().put("json", "Exception was thrown"); } return result; } }
When the controller looks like it does above, the advice code doesn't run even though the exception gets thrown (by getting /token/exception/true).Code:package demo.service; import java.sql.SQLException; import java.util.List; import demo.data.AuthToken; import org.apache.log4j.Logger; import org.springframework.stereotype.Service; @Service public class AuthTokenService { private Logger logger = Logger.getLogger(AuthTokenService.class); private static final AuthTokenService instance = new AuthTokenService(); public static final AuthTokenService getInstance() { return instance; } /** * Do not use. Only public because of aspectj. */ public AuthTokenService() { authtokenhandler = HandlerManagerSingleton.getAuthTokenHandlerInstance(); } public AuthToken causeExceptionInService(boolean shouldIThrowException) throws Exception { if(shouldIThrowException) { throw new Exception("A major error occured!"); } return new AuthToken(); } }
However!
The Advice executes just fine if I change the controller to look like the following, but this doesn't let me handle the exception. All the documentation etc seems to indicate that I should be able to "pick up" the exception getting thrown from the Service class, even though it gets caught in the Controller.
Code:package demo.controller; import demo.service.AuthTokenService; import demo.ServiceManagerSingleton; import demo.view.JSONView; import org.jdom.Document; import org.jdom.Element; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; @Controller @RequestMapping(value="/token") public class TokenController { private AuthTokenService authTokenService = null; public TokenController() throws Exception { authTokenService = ServiceManagerSingleton.getAuthTokenServiceInstance(); } @RequestMapping(value="/exception/{throwException}") public ModelAndView causeException(@PathVariable boolean throwException) throws Exception { ModelAndView result = new ModelAndView(new JSONView()); authTokenService.causeExceptionInService(throwException); result.getModelMap().put("json", "Everything went better then expected"); return result; } }
I haven't used AspectJ for more then a few simple annotation-controlled proxy classes and I still have a lot to learn, but this has me stumped. If anything has any tips as to why I can't pick up the exception being thrown from the Service class, it is much appreciated.


Reply With Quote
