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