Прокси и UndeclaredThrowableException

import java.io.EOFException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public class ProxyDemo {
    private final ClassLoader loader = getClass().getClassLoader();
    private final InvocationHandler throwHandler = new InvocationHandler() {
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            throw (Throwable) args[0];
        }
    };
    public interface ThrowsIOException {
        Object run(Throwable toThrow) throws IOException;
    }

    public interface ThrowsEOFException {
        Object run(Throwable toThrow) throws EOFException;
    }

    public void testDeclaredExceptionIntersectionIsSubtype() throws Exception {
        ThrowsIOException instance = (ThrowsIOException) Proxy.newProxyInstance(loader,
                new Class[] {ThrowsIOException.class, ThrowsEOFException.class}, throwHandler);
        try {
            instance.run(new EOFException());
        } catch (EOFException expected) {
        }
        try {
            instance.run(new IOException());
        } catch (UndeclaredThrowableException expected) {
        }
        try {
            instance.run(new Exception());
        } catch (UndeclaredThrowableException expected) {
        }
    }

    public static void main(String[] args) throws Throwable {
        ProxyDemo cl = new ProxyDemo();
        cl.testDeclaredExceptionIntersectionIsSubtype();
    }
}

все, что я хочу спросить, это почему, когда код запускает инструкцию instance.run (new IOException ()), он генерирует исключение UndeclaredThrowableException?

в соответствии с документом оракула в методе invoke InvocationHandler, если этим методом генерируется проверенное исключение, которое не может быть назначено ни одному из типов исключений, объявленных в предложении throws метода интерфейса, тогда UndeclaredThrowableException, содержащее исключение, которое было сгенерировано этот метод будет сгенерирован при вызове метода в экземпляре прокси.

в этом случае IOException присваивается IOException, так почему он выбрасывает UndeclaredThrowableException вместо IOException?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
0
2 509
1

Ответы 1

Потому что, когда вы создаете Прокси из двух интерфейсы, которые имеют одинаковые сигнатуры методов, эти сигнатуры методов будут объединены в одна подпись, который удовлетворяет требованиям для обоих интерфейсов.

Поскольку EOFException наследуется от IOException, подпись метода будет

public Object run(Throwable toThrow) throws EOFException

Вы можете проверить это сами, создав фиктивные классы:

public class Test implements ThrowsIOException, ThrowsEOFException {
    @Override
    public Object run(Throwable toThrow) throws IOException // compiler error
    {
        return null;
    }
}

public class Test implements ThrowsIOException, ThrowsEOFException {
    @Override
    public Object run(Throwable toThrow) throws EOFException // valid
    {
        return null;
    }
}

Это потому, что вы можете сузить выбрасываемое исключение (переопределение throws IOException с помощью throws EOFException нормально), но вы не можете его расширить (переопределение throws EOFException с помощью throws IOException незаконно).

Таким образом, когда вы вызываете метод и генерируется EOFException, он соответствует сгенерированной подписи метода прокси (она объявлена), и все в порядке. Однако, когда вы бросаете IOException, он не подходит под подпись (не декларируется), и вы получаете UndeclaredThrowableException.

спасибо, а что будет если два интерфейса не могут быть объединены?

speed9 25.04.2018 13:50
newProxyInstance выкинет IllegalArgumentException
Max Vollmer 25.04.2018 13:52

Я нашел ответ в документе оракула, он о «методах, дублируемых в нескольких интерфейсах прокси», но все же спасибо за вашу помощь.

speed9 25.04.2018 14:44

Другие вопросы по теме