2012-04-27 2 views
5

Ho alcuni metodi che generano alcune eccezioni, e voglio usare AspectJ in giro per consigliare di calcolare il tempo di esecuzione e se viene lanciata qualche eccezione e accedere al log degli errori e continuare flusso ri-lanciare l'eccezione.Come rilanciare un'eccezione in AspectJ attorno a

Ho cercato di ottenere ciò seguendo ma eclipse dice "Tipo di eccezione non gestita".

Codice-contro cui aspectj è utilizzato: -

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; 
} 

Codice 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; 
} 
} 

Si prega di aiutare perché questo AspectJ non sta funzionando.

risposta

10

è possibile evitare le eccezioni e utilizzare solo un blocco try/finally senza la cattura. E se si ha realmente bisogno per registrare l'eccezione è possibile utilizzare un dopo aver lanciato consiglio, in questo modo:

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); 
    } 

} 
+0

grazie, questa è un'ottima soluzione semplice. –

6

Ho paura che non è possibile scrivere consigli per generare eccezioni che non vengono dichiarate per essere gettate nel punto di unione corrispondente. Per: http://www.eclipse.org/aspectj/doc/released/progguide/semantics-advice.html: "Una dichiarazione di avviso deve includere una clausola throws che elenca le eccezioni controllate che il corpo può lanciare.Questo elenco di eccezioni controllate deve essere compatibile con ciascun punto di unione del consiglio o un errore viene segnalato dal compilatore."

C'è stata discussione sulla mailing list aspectj su come migliorare questa situazione - vedere le discussioni in questo modo: http://dev.eclipse.org/mhonarc/lists/aspectj-dev/msg01412.html

ma in fondo quello che dovrete fare è un consiglio diverso per ogni variante di dichiarazione di eccezione. Ad esempio:

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

che consiglierà ovunque che abbia quelle 3 eccezioni.

1

C'è una soluzione alternativa "brutto" - Li ho trovati 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); 
    } 
}