У меня возникла непредвиденная проблема, связанная с выделением исключений и генериками Java в подписях. Не мудрствуя лукаво, код в вопросе (объяснение следует):Метод Java с общим аргументом, вызванным из результата блока catch
public class StackOverflowTest {
private static class WrapperBuilder {
public static <T> ResultWrapper of(final T result) {
return new ResultWrapper<>(result);
}
public static ResultWrapper of(final RuntimeException exc) {
return new ResultWrapper<>(exc);
}
}
private static class ResultWrapper<T> {
private final T result;
private final RuntimeException exc;
ResultWrapper(final T result) {
this.result = result;
this.exc = null;
}
ResultWrapper(final RuntimeException exc) {
this.result = null;
this.exc = exc;
}
public Boolean hasException() {
return this.exc != null;
}
public T get() {
if (hasException()) {
throw exc;
}
return result;
}
}
private static class WrapperTransformer {
public ResultWrapper<Result> getResult(ResultWrapper originalWrappedResult) {
if (originalWrappedResult.hasException()) {
try {
originalWrappedResult.get();
} catch (Exception e) {
return WrapperBuilder.of(e);
}
}
return originalWrappedResult; // Transformation is a no-op, here
}
}
private static class Result {}
WrapperTransformer wrapper = new WrapperTransformer();
@Test
public void testBehaviour() {
ResultWrapper wrappedResult = WrapperBuilder.of(new RuntimeException());
final ResultWrapper<Result> result = wrapper.getResult(wrappedResult);
assertTrue(result.hasException()); // fails!
}
}
Оставляя в стороне, на данный момент, вопросы плохого стиля (я полностью признаю, что есть есть лучшие способов сделать то, что я делаю ! здесь), это урезано и анонимная версия следующего бизнеса-логика:
- класса
ResultWrapper
оборачивает результат вызова к потоку службы. Он содержит либо результат вызова, или в результате исключения - класс
WrapperTransformer
отвечает за преобразование ResultWrapper каким-то образом (хотя, здесь, то «преобразование» является не-ор)
Тест данное выше не выполняется. Из отладки я решил, что это потому, что WrapperBuilder.of(e)
фактически вызывает общий метод (т. Е. of(final T result)
). Это (вроде) имеет смысл, если общие аргументы «жадные» - RuntimeException
- a T
, так что метод является разумным (хотя и непреднамеренным) выбором.
Однако, когда метод DownstreamWrapper::getResult
изменяется на:
// i.e. explicitly catch RuntimeException, not Exception
} catch (RuntimeException e) {
return WrapperBuilder.of(e)
}
, то испытание терпит неудачу - т.е. Exception
идентифицируется как RuntimeException
, не-родовое .of
метод вызывается, и таким образом, в результате чего ResultWrapper
имеет населенный exc
.
Это совершенно непонятно для меня. Я полагаю, что даже внутри предложения catch (Exception e)
e
сохраняет свой первоначальный тип (и сообщения регистрации System.out.println(e.getClass().getSimpleName()
предполагают, что это правда) - так как можно изменить «тип» улова, переопределить подпись общего метода?
Фантастический, спасибо! – scubbo