`jdkProxyObj.getClass().getMethod("xxx")` will throw `java.lang.NoSuchMethodException: jdk.proxy4.$Proxy61.xxx()` in the `native-image`.
wangliang181230 opened this issue · 13 comments
Jdk proxy object can't get method by the Method Class.getMethod(methodName)
in the native-image
.
jdkProxyObj.getClass().getMethod("xxx")
will throw java.lang.NoSuchMethodException: jdk.proxy4.$Proxy61.xxx()
in the native-image
.
Example project
https://github.com/wangliang181230/example__oracle_graal_issue-6079
Some code
TestInterface.java
public interface TestInterface {
void foo();
void bar();
}
ProxyReflectionExample.java
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyReflectionExample {
public static void main(String[] args) throws Exception {
TestInterface proxyObj = (TestInterface)Proxy.newProxyInstance(
ProxyReflectionExample.class.getClassLoader(),
new Class[] { TestInterface.class },
(proxy, method, args1) -> {
System.out.println("Method: " + method.getName() + ", Declaring Class: " + method.getDeclaringClass().getName());
return null;
});
try {
// It will throw `NoSuchMethodException` in `native-image`.
Method method = proxyObj.getClass().getMethod("foo");
System.out.println("Method: " + method.getName() + ", Declaring Class: " + method.getDeclaringClass().getName());
method.invoke(proxyObj);
method = proxyObj.getClass().getMethod("bar");
System.out.println("Method: " + method.getName() + ", Declaring Class: " + method.getDeclaringClass().getName());
method.invoke(proxyObj);
} catch (Throwable t) {
t.printStackTrace();
}
Thread.sleep(10000);
}
}
reflect-config.json
[
{
"name": "TestInterface",
"methods": [
{ "name": "foo", "parameterTypes": [] },
{ "name": "bar", "parameterTypes": [] }
]
}
]
Console output in JVM
Method: foo, Declaring Class: jdk.proxy1.$Proxy0
Method: foo, Declaring Class: TestInterface
Method: bar, Declaring Class: jdk.proxy1.$Proxy0
Method: bar, Declaring Class: TestInterface
Error log in native-image
java.lang.NoSuchMethodException: jdk.proxy4.$Proxy60.foo()
at java.base@17.0.6/java.lang.Class.getMethod(DynamicHub.java:2227)
at ProxyReflectionExample.main(ProxyReflectionExample.java:17)
Environment and versions:
- OS:
Windows 10
- GraalVM:
graalvm-ce-java17-22.3.1 Windows (amd64)
How can I solve this problem?
Do you expect the Proxy to be registered automatically? If not, you would need to register it manually. Please see https://www.graalvm.org/22.0/reference-manual/native-image/DynamicProxy/ -
Also, please add the GraalVM version, which you used.
Do you expect the Proxy to be registered automatically? If not, you would need to register it manually. Please see https://www.graalvm.org/22.0/reference-manual/native-image/DynamicProxy/ -
My question is not about dynamic proxy, but about the acquisition of dynamic proxy methods.
For example proxyObj.getClass().getMethod(methodName)
will throw NoSuchMethodException
in native-image
.
Of course, I have added the metadata of the interfaces to reflect-config.json
and proxy-config.json
and successfully created the proxy object in native-image
, but the class of the proxy object is dynamic and cannot be added the reflect metadata.
Also, please add the GraalVM version, which you used.
graalvm-ce-java17-22.3.1 Windows (amd64)
This will cause the semantic inconsistency of proxyObject.getClass().getMethod(methodName)
in JVM
and native-image
.
Could you maybe add the stacktrace and the config files to this issue?
Could you maybe add the stacktrace and the config files to this issue?
I modified the content of this issue. PTAL
Thank you for sharing this, we'll take a look into it shortly
This is currently not supported in the metadata. We should allow for proxies to be marked with an interface list:
{
"proxy": ["TestInterface"],
"methods": [
{ "name": "foo", "parameterTypes": [] },
{ "name": "bar", "parameterTypes": [] }
]
}
Until we introduce that feature, a possible workaround is to use initialization at build time. Rewrite the program in the following way:
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
interface TestInterface {
void foo();
void bar();
}
public class ProxyReflectionExample {
static class ProxyReflectionStatics {
static final TestInterface proxyObj = (TestInterface) Proxy.newProxyInstance(
ProxyReflectionExample.class.getClassLoader(),
new Class[]{TestInterface.class},
(proxy, method, args1) -> {
System.out.println("Method: " + method.getName() + ", Declaring Class: " + method.getDeclaringClass().getName());
return null;
});
}
public static void main(String[] args) throws Exception {
try {
// It will throw `NoSuchMethodException` in `native-image`.
Method method = ProxyReflectionStatics.proxyObj.getClass().getMethod("foo");
System.out.println("Method: " + method.getName() + ", Declaring Class: " + method.getDeclaringClass().getName());
method.invoke(ProxyReflectionStatics.proxyObj);
method = ProxyReflectionStatics.proxyObj.getClass().getMethod("bar");
System.out.println("Method: " + method.getName() + ", Declaring Class: " + method.getDeclaringClass().getName());
method.invoke(ProxyReflectionStatics.proxyObj);
} catch (Throwable t) {
t.printStackTrace();
}
Thread.sleep(10000);
}
}
and build it with:
native-image ProxyReflectionExample --initialize-at-build-time=ProxyReflectionExample\$ProxyReflectionStatics
@vjovanov
However, in many applications, it is not known which interface to proxy.
The above code is only an example I provided.