@Override
public Object methodInvoked(Class clazz, String methodName, Object instance, String[] paramTypes, Object[] params) throws Throwable {
InvocationPlan invocationPlan = new InvocationPlan(clazz, methodName, instance, paramTypes);
if (!invocationPlan.prepare()) {
reportNoShadowMethodFound(clazz, methodName, paramTypes);
return null;
}
if (strictI18n && !invocationPlan.isI18nSafe()) {
throw new I18nException("Method " + methodName + " on class " + clazz.getName() + " is not i18n-safe.");
}
try {
return invocationPlan.getMethod().invoke(invocationPlan.getShadow(), params);
} catch (IllegalArgumentException e) {
throw new RuntimeException(invocationPlan.getShadow().getClass().getName() + " is not assignable from " +
invocationPlan.getDeclaredShadowClass().getName(), e);
} catch (InvocationTargetException e) {
throw stripStackTrace(e.getCause());
}
}