RuntimeException распространение из метода, вызванного отражением

Я начинаю с кода. Этот метод вызывает метод с использованием отражения

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

и вызывает метод со следующим кодом, который генерирует PropertiesDontMatchException (время выполнения).

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

Дело в том, что мое исключение во время выполнения завернуто в InvocationTargetException и попало в первый фрагмент кода. Это не то, что я хочу. Но, согласно документации, это правильное поведение.

Итак, я придумал это решение

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

Является ли это правильным способом распространения моего исключения во время выполнения или есть ли лучшее решение этой проблемы?

1 ответ

Да, это правильная обработка ошибок в этом случае. Я бы только продлить тест на любой RuntimeException:

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

Или используйте Throwables класс утилиты из guava, если вы не возражаете использовать RuntimeException вместо пользовательского InternalException для отмеченных исключений:

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

Дополнительная обертка необходима для того, чтобы провести различие между вашим, например. ваш метод бросает IllegalAccessException и сам механизм отражения бросает его.

Подобный выбор дизайна API можно наблюдать с помощью Future.get() - в случае исключения, вызванного асинхронным заданием ExecutionException забрасывается фактическое исключение.

licensed under cc by-sa 3.0 with attribution.