Issue
I have moved my Clojure application from jdk8 to jdk11 (Zulu JRE 11) and it started to fail to invoke a default method on an interface, whose implementation is machine-generated (and looks something like #object[com.sun.proxy.$Proxy110 0x28466aa5 nil]
).
I do
(.someDefaultMethod iinterface-impl)
and get
java.lang.IllegalAccessException: access to public member failed:
my.IInterface.someDefaultMethod[Ljava.lang.Object;@172aedbe/invokeSpecial, from my.IInterface/2 (unnamed module @627551fb)
at java.base/java.lang.invoke.MemberName.makeAccessException(MemberName.java:942)
at java.base/java.lang.invoke.MethodHandles$Lookup.checkAccess(MethodHandles.java:2206)
at java.base/java.lang.invoke.MethodHandles$Lookup.checkMethod(MethodHandles.java:2146)
at java.base/java.lang.invoke.MethodHandles$Lookup.getDirectMethodCommon(MethodHandles.java:2290)
at java.base/java.lang.invoke.MethodHandles$Lookup.getDirectMethodNoSecurityManager(MethodHandles.java:2283)
at java.base/java.lang.invoke.MethodHandles$Lookup.unreflectSpecial(MethodHandles.java:1798)
at my.SomeService.invoke(SomeService.java:305)
Is there any solution? Thank you!
Solution
It turns out the error was not due to Clojure but due to the way calling the default method was coded in the proxy handler's invoke
:
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Proxy: calling " + method);
// Default methods are public non-abstract instance methods
// declared in an interface.
if (((method.getModifiers() & (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) ==
Modifier.PUBLIC) && method.getDeclaringClass().isInterface()) {
// see https://rmannibucau.wordpress.com/2014/03/27/java-8-default-interface-methods-and-jdk-dynamic-proxies/
final Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class);
if (!constructor.isAccessible()) {
constructor.setAccessible(true);
}
final Class<?> declaringClass = method.getDeclaringClass();
return constructor.newInstance(declaringClass, MethodHandles.Lookup.PRIVATE)
.unreflectSpecial(method, declaringClass)
.bindTo(proxy)
.invokeWithArguments(args);
}
return null;
}
Answered By - Jakub Holý
Answer Checked By - Pedro (JavaFixing Volunteer)