Announcement Announcement Module
Collapse
No announcement yet.
Unable to get @AfterThrowing to run if the calling class has try/catch Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Unable to get @AfterThrowing to run if the calling class has try/catch

    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.

  • #2
    Use spring because you aren't using spring. For some reason you feel the urge to create your own lookup mechanism and bypass spring. Work WITH the framework not AGAINST the framework and the latter is what you are doing.

    Don't create instances and singletons yourself let spring inject them, that way spring can also properly create proxies and will inject a proxied instance (currently that isn't happening).

    Comment


    • #3
      Doh! This is an old project that we are "springifying"

      Thanks for the tip! It solved the problem and at the same time made the code a lot smoother. I am now @Autowired'ing my service instead of using the old ServiceManager class.

      Win-win!

      Comment

      Working...
      X