How to re-throw exception in AspectJ around advise

人盡茶涼 提交于 2019-12-04 12:51:36

问题


I have some methods which throws some exception, and I want to use AspectJ around advise to calculate the execution time and if some exception is thrown and to log into error log and continue the flow by re-throwing the exception.

I tried to achieve this by following but eclipse says "Unhandled Exception type".

Code-against whom aspectj is to used :-

public interface Iface {
    public void reload() throws TException;

    public TUser getUserFromUserId(int userId, String serverId) throws ResumeNotFoundException, TException;

    public TUser getUserFromUsername(String username, String serverId) throws  ResumeNotFoundException, TException;

    public TResume getPartialActiveProfileFromUserId(int userId, int sectionsBitField, String serverId) throws ResumeNotFoundException, UserNotFoundException;

    public TResume getPartialActiveProfileFromUsername(String username, int sectionsBitField, String serverId) throws ResumeNotFoundException, UserNotFoundException, TException;
}

Code aspectj :-

public aspect AspectServerLog {

public static final Logger ERR_LOG = LoggerFactory.getLogger("error");

Object around() : call (* com.abc.Iface.* (..)) {
    Object ret;
    Throwable ex = null;

    StopWatch watch = new Slf4JStopWatch();

    try {
    ret = proceed();
    }catch (UserNotFoundException e) {
    ex = e ;
     throw e ;
    } catch (ResumeNotFoundException e) {
    ex = e ;
    throw e ;
    } catch (Throwable e) {
    ex = e ;
    throw new RuntimeException(e);
    }finally{

    watch.stop(thisJoinPoint.toShortString());

    if(ex!=null){
        StringBuilder mesg = new StringBuilder("Exception in ");
        mesg.append(thisJoinPoint.toShortString()).append('(');
        for(Object o : thisJoinPoint.getArgs()) {
        mesg.append(o).append(',');
        }
        mesg.append(')');

        ERR_LOG.error(mesg.toString(), ex);
        numEx++;
    }

   }
return ret;
}
}

Please help why this AspectJ is not working.


回答1:


you can avoid catching the exceptions and just use a try/finally block without the catch. And if you really need to log the exception you can use an after throwing advice, like this:

public aspect AspectServerLog {

    public static final Logger ERR_LOG = LoggerFactory.getLogger("error");

    Object around() : call (* com.abc.Iface.* (..)) {

        StopWatch watch = new Slf4JStopWatch();

        try {
            return proceed();
        } finally {
            watch.stop(thisJoinPoint.toShortString());
        }
    }

    after() throwing (Exception ex) : call (* com.abc.Iface.* (..)) {
        StringBuilder mesg = new StringBuilder("Exception in ");
        mesg.append(thisJoinPoint.toShortString()).append('(');
        for (Object o : thisJoinPoint.getArgs()) {
            mesg.append(o).append(',');
        }
        mesg.append(')');

        ERR_LOG.error(mesg.toString(), ex);
    }

}



回答2:


I'm afraid you cannot write advice to throw exceptions that aren't declared to be thrown at the matched join point. Per: http://www.eclipse.org/aspectj/doc/released/progguide/semantics-advice.html : "An advice declaration must include a throws clause listing the checked exceptions the body may throw. This list of checked exceptions must be compatible with each target join point of the advice, or an error is signalled by the compiler."

There has been discussion on the aspectj mailing list about improving this situation - see threads like this: http://dev.eclipse.org/mhonarc/lists/aspectj-dev/msg01412.html

but basically what you will need to do is different advice for each variant of exception declaration. For example:

Object around() throws ResumeServiceException, ResumeNotFoundException, TException: 
  call (* Iface.* (..) throws ResumeServiceException, ResumeNotFoundException, TException) {

that will advise everywhere that has those 3 exceptions.




回答3:


There is an "ugly" workaround - I found them in Spring4 AbstractTransactionAspect

Object around(...): ... {
    try {
        return proceed(...);
    }
    catch (RuntimeException ex) {
        throw ex;
    }
    catch (Error err) {
        throw err;
    }
    catch (Throwable thr) {
        Rethrower.rethrow(thr);
        throw new IllegalStateException("Should never get here", thr);
    }
}

/**
 * Ugly but safe workaround: We need to be able to propagate checked exceptions,
 * despite AspectJ around advice supporting specifically declared exceptions only.
 */
private static class Rethrower {

    public static void rethrow(final Throwable exception) {
        class CheckedExceptionRethrower<T extends Throwable> {
            @SuppressWarnings("unchecked")
            private void rethrow(Throwable exception) throws T {
                throw (T) exception;
            }
        }
        new CheckedExceptionRethrower<RuntimeException>().rethrow(exception);
    }
}


来源:https://stackoverflow.com/questions/10346750/how-to-re-throw-exception-in-aspectj-around-advise

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!