Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UndeclaredThrowableException thrown by IndexOutOfBoundsException

I am using the decorator pattern for a List<WebElement>.Part of this decoration entails using a proxy.

When I call get(index) with an index that is out of bounds, it throws an IndexOutOfBounds exception, which is then caught by the proxy, and wrapped with an UndeclaredThrowableException.

My understanding is that it should only do this if its a checked exception. IndexOutOfBounds is an unchecked exception, so why is it getting wrapped?

It still gets wrapped even if I add throws IndexOutOfBounds to my invoke function.

Here's my code:

@SuppressWarnings("unchecked")
public WebElementList findWebElementList(final By by){
    return new WebElementList(
            (List<WebElement>) Proxy.newProxyInstance(this.getClass().getClassLoader(),
                    new Class<?>[] { List.class }, new InvocationHandler() {
        // Lazy initialized instance of WebElement
        private List<WebElement> webElements;

        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            if (webElements == null) {
                webElements = findElements(by);
            }
            return method.invoke(webElements, args);
        }
    }), driver);
}

Here's part of my stacktrace:

java.lang.reflect.UndeclaredThrowableException
at com.sun.proxy.$Proxy30.get(Unknown Source)
at org.lds.ldsp.enhancements.WebElementList.get(WebElementList.java:29)
...
Caused by: java.lang.IndexOutOfBoundsException: Index: 1, Size: 1
at java.util.ArrayList.rangeCheck(ArrayList.java:604)
at java.util.ArrayList.get(ArrayList.java:382)
... 41 more
like image 660
Nathan Merrill Avatar asked Oct 30 '13 18:10

Nathan Merrill


2 Answers

Vic Jang is right. You need to wrap the invocation in try-catch and rethrow the inner exception.

try {
  return method.invoke(webElements, args);
} catch (InvocationTargetException ite) {
  throw ite.getCause();
}

The reason is that "Method.invoke" wraps in InvocationTargetException those exceptions which are thrown in the method's code.

java.lang.reflect.Method:

Throws:
...
InvocationTargetException - if the underlying method throws an exception.

java.lang.reflect.InvocationTargetException:

InvocationTargetException is a checked exception that wraps an exception thrown by an invoked method or constructor.

The proxy object's class doesn't have InvocationTargetException declared among its "throws". That leads to UndeclaredThrowableException.

like image 163
Zorg Avatar answered Nov 15 '22 19:11

Zorg


I don't have enough reputation to comment. Your problem seems very similar to this one

You can look at the solution there and see if that works.

In short, you need to wrap your method.invoke into try{}, catch the exception, and throw it again.

like image 33
Vic Jang Avatar answered Nov 15 '22 18:11

Vic Jang