2012-04-13 11 views
3

aufgerufen wird Ich fange direkt mit dem Code an. Dies ruft eine Methode unter Verwendung von ReflexionsRuntimeException-Propagierung von einer Methode, die durch Reflexion

try { 
    Method method = states.getClass().getDeclaredMethod(
      getCurrentStateId() + "_" + request.getEvent()); 
    states.setData(request, dataManager); 
    method.invoke(states); 
} catch (NoSuchMethodException e) { 
    logger.debug("Method " + getCurrentStateId() + "_" + request.getEvent() 
      + " cannot be found - invocation not performed.", e); 
} catch (IllegalArgumentException e) { 
    throw new InternalException("Method invocation with reflection failed.", e); 
} catch (IllegalAccessException e) { 
    throw new InternalException("Method invocation with reflection failed.", e); 
} catch (InvocationTargetException e) { 
    throw new InternalException("Method invocation with reflection failed.", e); 
} 

und ruft die Methode durch den folgenden Code, der eine PropertiesDontMatchException (Laufzeit) führt.

... 
if (totalCredits < minimumCredits || totalCredits > maximumCredits) { 
    throw new PropertiesDontMatchException("Minimum amount of credits=" + minimumCredits 
      + ", maximum amount of credits=" + maximumCredits + ". Your amount of credits="     + totalCredits + ". You have to modify your set of subjects."); 
} 
... 

Die Sache ist die, dass meine Laufzeitausnahme in InvocationTargetException und in den ersten Code-Schnipseln gefangen gewickelt wird. Das ist nicht was ich will. Aber nach der Dokumentation ist es das richtige Verhalten.

So kam ich mit dieser Lösung bis

... 
} catch (InvocationTargetException e) { 
    if (e.getCause() instanceof PropertiesDontMatchException) { 
     throw (PropertiesDontMatchException) e.getCause(); 
    } 
    throw new InternalException("Method invocation with reflection failed.", e); 
} 
... 

Ist dies die richtige Art und Weise, wie meine Laufzeitausnahme zu propagieren oder gibt es eine bessere Lösung für dieses Problem?

Antwort

4

Ja, das ist die korrekte Fehlerbehandlung in diesem Fall. Ich würde nur Ihr Test für jeden RuntimeException verlängern:

} catch (InvocationTargetException e) { 
    if (e.getCause() instanceof RuntimeException) { 
     throw (RuntimeException) e.getCause(); 
    } 
    if (e.getCause() instanceof Error) { 
     throw (Error) e.getCause(); 
    } 
    throw new InternalException("Method invocation with reflection failed.", e); 
} 

Oder verwenden Throwables utility class von statt, wenn Sie nicht anstelle von benutzerdefinierten InternalException für geprüfte Ausnahmen mit RuntimeException nichts dagegen:

} catch (InvocationTargetException e) { 
    throw Throwables.propagate(e.getCause()); 
} 

Die zusätzliche Verpackung ist notwendig, um zwischen Ihrem z Ihre Methode werfen IllegalAccessException und Reflexionsmechanismus selbst wirft es.

Ähnliche API-Design-Wahl kann mit Future.get() beobachtet werden - im Falle der Ausnahme von asynchronen Auftrag geworfen ExecutionException wird geworfen, um die tatsächliche Ausnahme zu wickeln.

+0

Ich kann dies nicht tun, weil ich andere Laufzeitausnahmen in InternalException umbrechen möchte, die dann als 500 Interner Fehler an den Client zurückgegeben wird. Die Eigenschaft ..Exception wird als 400 ungültige Anforderung zurückgegeben. Aber danke für die Antwort ... – user219882

+0

Was ist, wenn 'e.getCause() instanceof Error'? – Saintali

+0

@Saintali: Sie haben Recht, ich habe meine Antwort aktualisiert und Guava Tipp hinzugefügt. Vielen Dank! –

Verwandte Themen