Clojure не может вызвать метод интерфейса по умолчанию для java 11 из-за IllegalAccessException - PullRequest
2 голосов
/ 24 января 2020

Я переместил свое приложение Clojure из jdk8 в jdk11 (Zulu JRE 11), и оно стало не в состоянии вызывать метод по умолчанию в интерфейсе, реализация которого генерируется машиной (и выглядит примерно так: #object[com.sun.proxy.$Proxy110 0x28466aa5 nil]).

Я делаю

(.someDefaultMethod iinterface-impl)

и получаю

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)

Есть ли какое-нибудь решение? Спасибо!

1 Ответ

0 голосов
/ 26 января 2020

Оказывается, ошибка не из-за Clojure, а из-за того, что вызов метода по умолчанию был закодирован в обработчике прокси 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;
}
...