Question

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
Was it helpful?

Solution

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.

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top