I'm trying to get native-image to work in this situation: 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.
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 {
}
}
The exception I'm getting is
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
When running with java -jar
, it works just fine btw.