Announcement Announcement Module
Collapse
No announcement yet.
Unable to get @AfterThrowing to run by service class (but works fine for controller) Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Unable to get @AfterThrowing to run by service class (but works fine for controller)

    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:
    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;
    	}
    }
    And my Service class, this is the class where I was hoping the advice would execute:
    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();
    	}
    }
    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).

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