vendredi 19 février 2016

java.lang.reflect.Proxy: Huge exception stack trace

Here is a simple Java application:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class Main {

    interface MyInterface {
        void myMethod();
    }

    public static void main(String[] args) {
        MyInterface myInterface = (MyInterface) Proxy.newProxyInstance(Main.class.getClassLoader(), new Class[] {MyInterface.class},
            new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    return method.invoke(proxy, args);
                }
            });
        myInterface.myMethod();
    }
}

I would expect to get a simple StackOverflowError here, because I am recursively calling the same method on the proxy instance.

However, the stack trace produced by the exception contains millions of lines and hundreds of MBs in size.

The first part of the stack trace starts like this:

java.lang.reflect.UndeclaredThrowableException
    at $Proxy0.myMethod(Unknown Source)
    at Main.main(Main.java:22)
Caused by: java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at Main$1.invoke(Main.java:18)
    ... 2 more
Caused by: java.lang.reflect.UndeclaredThrowableException
    at $Proxy0.myMethod(Unknown Source)
    ... 7 more
Caused by: java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at Main$1.invoke(Main.java:18)
    ... 8 more

and extends to:

Caused by: java.lang.reflect.UndeclaredThrowableException
    at $Proxy0.myMethod(Unknown Source)
    ... 1022 more

Then follow millions of lines like:

Caused by: java.lang.reflect.InvocationTargetException
    at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at Main$1.invoke(Main.java:18)
    at $Proxy0.myMethod(Unknown Source)
    at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at Main$1.invoke(Main.java:18)
    .......

and:

Caused by: java.lang.reflect.UndeclaredThrowableException
    at $Proxy0.myMethod(Unknown Source)
    at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at Main$1.invoke(Main.java:18)
    at $Proxy0.myMethod(Unknown Source)
    at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at Main$1.invoke(Main.java:18)
    .......

The last printed line is (after the repeating sequence above):

Exception: java.lang.StackOverflowError thrown from the UncaughtExceptionHandler in thread "main"

I suspected that stack trace generation mechanism was calling some methods on the proxy instance (maybe toString to print it, or something else), thus repeating the recursion over and over again (because each method call on the proxy leads to infinite recursion), but the total count of proxy method executions is 1919 (measured by incrementing a counter in the InvocationHandler.invoke method).

In my real use case I fixed the infinite recursion issue of course; I am just curious if anyone knows if this is some bug or there is a reasonable explanation?

Java version:

java version "1.8.0_65"
Java(TM) SE Runtime Environment (build 1.8.0_65-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.65-b01, mixed mode)





Aucun commentaire:

Enregistrer un commentaire