Русские Блоги
Решение java.lang.reflect.UndeclaredThrowableException
Предисловие
Я начал писать веб-интерфейс в последние два дня, так как бэк-энд проекта — мой единственный человек, писать его медленно. , Обнаружено много странных проблем, и в основном их может решить только один человек. Сегодня днем надолго задержался на этом вопросе. Теперь у меня все еще болит мозг.
проблема
Бизнесу необходимо реализовать функцию перехвата параметров запроса. Проверьте, включен ли токен. Проект реализован на базе springmvc, здесь естественно использовать технологию пружинного аспекта. Перехватите все запросы контроллера, а затем проверьте, передан ли параметр токена. Если он не переносится, генерируется настраиваемое исключение. Затем вызовите единый класс обработки исключений для его обработки.
Участвуют следующие классы:
Пользовательский класс исключения
Единый класс обработки исключений
Интерфейс вызывается в это время, и ожидается, что он должен
На самом деле возвращено
Ошибка консоли выглядит следующим образом:
Это странно. Почему созданное мной настраиваемое исключение превратилось в UndeclaredThrowableException, которое не могло быть обработано единым обработчиком исключений.
причина
Через поисковик наконец нашел причину:
Наш класс обработки исключений на самом деле является реализацией динамического прокси.
Если исключение является проверенным исключением и не объявлено в интерфейсе динамического прокси, оно будет заключено в оболочку UndeclaredThrowableException.
Определенное нами настраиваемое исключение определяется как проверенное исключение, что приводит к его упаковке как UndeclaredThrowableException.
решить
Узнать причину очень просто. Либо вызовите непроверенное исключение java.lang.RuntimeException или java.lang.Error, либо интерфейс должен объявить исключение.
Здесь вы можете изменить настраиваемое исключение как исключение времени выполнения.
1. По возможности определяйте настраиваемые исключения как исключения времени выполнения.
2. Понятие исключения неясно. Фундамент не прочный.
Getting UndeclaredThrowableException instead of my own exception
When I use a user that does not have permissions, I get java.lang.reflect.UndeclaredThrowableException instead of AccessException .
![]()
1 Answer 1
AccessException is a checked exception, but it was thrown from the method that doesn’t declare it in its throws clause (actually — from the aspect intercepting that method). It’s an abnormal condition in Java, so your exception is wrapped with UndeclaredThrowableException , which is unchecked.
Когда Java Создает исключение UndeclaredThrowableException?
В этом уроке мы рассмотрим, что заставляет Java выбрасывать экземпляр UndeclaredThrowableException exception.
Во-первых, мы начнем с небольшой теории. Затем мы попытаемся лучше понять природу этого исключения с помощью двух реальных примеров.
2. Исключение UndeclaredThrowableException
Теоретически говоря, Java создаст экземпляр UndeclaredThrowableException , когда мы попытаемся создать необъявленное проверенное исключение . То есть мы не объявляли проверенное исключение в предложении throws , но мы выбрасываем это исключение в теле метода.
Можно возразить, что это невозможно, так как компилятор Java предотвращает это с помощью ошибки компиляции. Например, если мы попытаемся скомпилировать:
Компилятор Java завершает работу с сообщением:
Даже если выбрасывание необъявленных проверенных исключений может не произойти во время компиляции, это все еще возможно во время выполнения. Например, давайте рассмотрим прокси-сервер времени выполнения, перехватывающий метод, который не создает никаких исключений:
Если прокси-сервер сам создает проверенное исключение, с точки зрения вызывающего, метод save создает это проверенное исключение. Вызывающий, вероятно, ничего не знает об этом прокси-сервере и будет обвинять save в этом исключении.
В таких обстоятельствах Java обернет фактическое проверенное исключение в исключение UndeclaredThrowableException и вместо этого выбросит исключение UndeclaredThrowableException . Стоит отметить, что UndeclaredThrowableException само по себе является непроверенным исключением.
Теперь, когда мы достаточно знаем об этой теории, давайте рассмотрим несколько реальных примеров.
3. Динамический прокси-сервер Java
В качестве нашего первого примера давайте создадим runtime proxy для java.util.Перечислите интерфейс и перехватите вызовы его методов. Во-первых, мы должны реализовать интерфейс InvocationHandler и поместить туда дополнительную логику:
Этот прокси-сервер выдает проверенное исключение, если проксируемый метод имеет размер . В противном случае он вызовет непроверенное исключение.
Давайте посмотрим, как Java справляется с обеими ситуациями. Сначала мы вызовем метод List.size() :
Как показано выше, мы создаем прокси-сервер для интерфейса List и вызываем на нем метод size . Прокси, в свою очередь, перехватывает вызов и выдает проверенное исключение. Затем Java обертывает это проверенное исключение внутри экземпляра UndeclaredThrowableException. Это происходит потому, что мы каким-то образом выбрасываем проверенное исключение, не объявляя его в объявлении метода.
Если мы вызовем любой другой метод в интерфейсе List :
Поскольку прокси-сервер выдает непроверенное исключение, Java позволяет исключению распространяться как есть.
4. Пружинный аспект
То же самое происходит, когда мы выбрасываем проверенное исключение в аспекте Spring , в то время как рекомендуемые методы их не объявляли. Давайте начнем с аннотации:
Теперь мы собираемся посоветовать все методы, аннотированные этой аннотацией:
В принципе, этот совет заставит все аннотированные методы выдавать проверенное исключение, даже если они не объявили такое исключение . Теперь давайте создадим сервис:
Если мы вызовем аннотированный метод, Java выдаст экземпляр UndeclaredThrowableException exception:
Как показано выше, Java инкапсулирует фактическое исключение в качестве причины и вместо этого вызывает исключение UndeclaredThrowableException .
5. Заключение
В этом уроке мы увидели, что заставляет Java выбрасывать экземпляр UndeclaredThrowableException exception.
Proxy and Checked Exceptions in Java
By Eugene Petrenko November 22, 2018 Comment Tweet Like
java.lang.reflect.Proxy and checked exceptions
On-the-Fly Proxy
Say on have an interface Foo with several (hundreds) methods. Is it possible to implement an interface on-the-fly? Without having an implementation code? Yes. It is possible. The standard possibility is java.lang.reflect.Proxy. The newProxyInstance method helps to create an on-the-fly implementation. One provides an interceptor object that is called for every method invocation on the interface implementation instance.
Besides the standard Proxy API, there are libraries, that do the same thing, for example, Byte Buddy or CGLIB.
In this post, we will use the standard JRE API — java.lang.reflect.Proxy
Proxy and Checked Exceptions
Let’s consider the following code in Java:
The code is trivial. We have the interface Foo , and we implement it via Proxy#newProxyInstance . The implementation of the Proxy instance throws an exception of type Exception . Will we have the exception of type Exception as a result?
Running the Example
Let’s execute the example and see what we have:
The answer is NO. We have java.lang.reflect.UndeclaredThrowableException exception.
Checked Exceptions in Java
As we all know, Java has checked exceptions. It means one declares what exceptions are possibly thrown from a method. The main class of all exceptions is java.lang.Throwable.
In Java language, we use throws to indicate that a method may throw an exception. For example, throws IOException .
There are two specific sub-classes of Throwable , which does not require to be declared by the throws keyword — java.lang.Error and java.lang.RuntimeException . All sub-classes of those two types are free to throw without declaration.
Proxy and UndeclaredThrowableException
The UndeclaredThrowableException is the specific exception type that is used in the create a proxy implementation of an interface to preserve checked exceptions in Java. As we see from the Javadoc, the exception is used to wrap any checked exceptions that are not declared with the throws block in the interface declaration.
Proxy and JVM Languages
JVM ecosystem is huge. There are many languages for the JVM, including Kotlin, Groovy, Scala and so on, that does not have checked exceptions.
Checked exceptions are checked by the compiler, on the JVM bytecode level, there is no difference between exceptions at all.
It is quite easy to get UndeclaredThrowableException at some unexpected places if mixing such languages with java.lang.reflect.Proxy !
For example, in Kotlin:
The same code reads correctly but does not work. It is allowed in Kotlin to throw Exception from a method (because exceptions are not checked), but it will not work via the java.lang.reflect.Proxy . We will have the following execution result
Fixing the UndeclaredThrowableException
To avoid the UndeclaredThrowableException one need to declare the exceptions explicitly with throws block. That solves the problem in Java example above. Similarly, it solves the problem in the Kotlin snippet too: we add the @Throws(Exception::class) annotation on the bar function.
One may have a look at the implementation of the Proxy#newProxyInstance in the sources of JVM. It turns out it is not possible to disable that logic in the implementation. One is not allowed to breach Java’s checked exceptions with Proxy#newProxyInstance .
There are two ways. One is to declare throws for all interfaces that are used with Proxy#newProxyInstance . Of course, it is too easy to forget doing in languages without checked exceptions. Tests may help.
An alternative could be to implement or use another variant of the Proxy#newProxyInstance , that does not do the check. Let me know in the comments if you’d like to learn more, how exactly the Proxy#newProxyInstance or similar proxies are implemented.