graal icon indicating copy to clipboard operation
graal copied to clipboard

[GR-51239] GraalVM native-image dynamic proxy fails to invoke methods defined in super-interfaces

Open yrn1 opened this issue 1 year ago • 3 comments

Describe the issue I have a dynamic proxy on an interface, which has a super-interface that declares a default method. Invoking this default method from the sub-interface always fails.

Steps to reproduce the issue

I tried to put various entries in proxy-config.json and reflect-config.json, including what was generated by the native-image agent, but I just cannot get it to work. I tried with GraalVM 21 and 17. Any ideas what I'm doing wrong? Here's the code. I know it is a bit of a contrived example. This is the minimal version I could extract from a much more complicated code-base.

package nativetest;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class Main {
    public static void main(String[] args) {
        Class<?> c = TestSubInterface.class;
        TestInvocationHandler<?> handler = new TestInvocationHandler<>(c);
        TestSubInterface proxy = (TestSubInterface) Proxy.newProxyInstance(Main.class.getClassLoader(),
                new Class<?>[] { c }, handler);

        System.out.println("Result: " + proxy.doSomething());
    }

    public static class TestInvocationHandler<T> implements InvocationHandler {
        private final Class<T> configClass;

        public TestInvocationHandler(Class<T> configClass) {
            this.configClass = configClass;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            MethodHandle methodHandle = MethodHandles.lookup()
                    .findSpecial(configClass, method.getName(),
                            MethodType.methodType(method.getReturnType(), method.getParameterTypes()),
                            configClass);
            return methodHandle.bindTo(proxy).invoke();
        }
    }

    public interface TestInterface {
        default String doSomething() {
            System.out.println("Doing something");
            return "Something done";
        }
    }

    public interface TestSubInterface extends TestInterface {

    }
}

While this works fine when run with java -jar, it fails when run as native image with following error:

Exception in thread "main" java.lang.reflect.UndeclaredThrowableException
    at jdk.proxy4/jdk.proxy4.$Proxy48.doSomething(Unknown Source)
    at nativetest.Main.main(Main.java:17)
    at [email protected]/java.lang.invoke.LambdaForm$DMH/sa346b79c.invokeStaticInit(LambdaForm$DMH)
Caused by: java.lang.NoSuchMethodException: no such method: nativetest.Main$TestSubInterface.doSomething()String/invokeSpecial
    at [email protected]/java.lang.invoke.MemberName.makeAccessException(MemberName.java:915)
    at [email protected]/java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:994)
    at [email protected]/java.lang.invoke.MethodHandles$Lookup.resolveOrFail(MethodHandles.java:3750)
    at [email protected]/java.lang.invoke.MethodHandles$Lookup.findSpecial(MethodHandles.java:3097)
    at nativetest.Main$TestInvocationHandler.invoke(Main.java:30)
    ... 3 more
Caused by: java.lang.NoSuchMethodError: nativetest.Main$TestSubInterface.doSomething()
    at org.graalvm.nativeimage.builder/com.oracle.svm.core.methodhandles.Util_java_lang_invoke_MethodHandleNatives.resolve(Target_java_lang_invoke_MethodHandleNatives.java:335)
    at [email protected]/java.lang.invoke.MethodHandleNatives.resolve(MethodHandleNatives.java:213)
    at [email protected]/java.lang.invoke.MemberName$Factory.resolve(MemberName.java:962)
    at [email protected]/java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:991)
    ... 6 more

Describe GraalVM and your environment:

  • Both graalvm-jdk-17.0.9+11.1 and graalvm-jdk-21.0.1+12.1
  • OS: Linux (tested on CentOS 7, Oracle Linux 8 and WSL2)
  • Architecture: AMD64

yrn1 avatar Nov 06 '23 13:11 yrn1

Anyone?

yrn1 avatar Nov 20 '23 10:11 yrn1

Thank you for reaching out about this, we'll take a look into it shortly

oubidar-Abderrahim avatar Jan 09 '24 15:01 oubidar-Abderrahim

Thank you for reporting this issue! This is a known problem and it is tracked with this roadmap item: https://github.com/oracle/graal/issues/7476

ETA for the fix is GraalVM for JDK 23. We will make sure to test this example while implementing the functionality.

vjovanov avatar Jan 31 '24 18:01 vjovanov

The ability to specify methods of proxy classes in the reachability metadata was added in #8822

loicottet avatar Jul 18 '24 09:07 loicottet