java.lang.LinkageError при вызове метода класса через MethodHandles дважды

UPD: Цель данного кода - в режиме выполнения загружать классы из файлов, находящихся рядом с исполняемой программой. При этом один и тот же класс должен быть загружен много раз(есстественно не одним и тем же classLoader'ом) и каждый раз загружаются разные версии этого класса. Загрузить один раз и дальше использовать нельзя.
Привожу ниже упрощённый минимальный код для воспроизведения проблемы

import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;

public class Main {
    public static void main(String[] args) throws Throwable
    {
        method(); //OK
        method(); //FAIL
    }
    public static void method() throws Throwable
    {
        DefineClassLoader classLoader = new DefineClassLoader(new URL[0], ClassLoader.getSystemClassLoader());
        byte[] clazzBytes = Files.readAllBytes(Paths.get("TestedClass.class"));
        Class<?> clazz = classLoader.rawDefine("TestedClass", clazzBytes);
        Object object = MethodHandles.publicLookup().findStatic(clazz, "getDefault", MethodType.methodType(clazz)).invoke();
        System.out.println(object.getClass().getName());
    }
}
import java.net.URL;
import java.net.URLClassLoader;

public class DefineClassLoader extends URLClassLoader {

    public DefineClassLoader(URL[] urls, ClassLoader parent) {
        super(urls, parent);
    }

    public Class<?> rawDefine(String name, byte[] bytes)
    {
        return defineClass(name, bytes, 0, bytes.length);
    }
}

Еще понадобится ОТДЕЛЬНО скомплировать класс TestedClass через javac

public class TestedClass {
    public String a;
    public static TestedClass getDefault()
    {
        TestedClass ret = new TestedClass();
        ret.a = "OK";
        return ret;
    }
}

На втором вызове метода вылетает следующее исключение:

Exception in thread "main" java.lang.IllegalAccessException: no such method: TestedClass.getDefault()TestedClass/invokeStatic
        at java.base/java.lang.invoke.MemberName.makeAccessException(MemberName.java:959)
        at java.base/java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:1101)
        at java.base/java.lang.invoke.MethodHandles$Lookup.resolveOrFail(MethodHandles.java:2055)
        at java.base/java.lang.invoke.MethodHandles$Lookup.findStatic(MethodHandles.java:1112)
        at Main.method(Main.java:18)
        at Main.main(Main.java:11)
Caused by: java.lang.LinkageError: loader constraint violation: when resolving method 'TestedClass TestedClass.getDefault()' the class loader 'bootstrap' of the current class, java/lang/Object, and the class loader DefineClassLoader @681a9515 for the method's defining class, TestedClass, have different Class objects for the type TestedClass used in the signature (java.lang.Object is in module java.base of loader 'bootstrap'; TestedClass is in unnamed module of loader DefineClassLoader @681a9515, parent loader 'app')
        at java.base/java.lang.invoke.MethodHandleNatives.resolve(Native Method)
        at java.base/java.lang.invoke.MemberName$Factory.resolve(MemberName.java:1070)
        at java.base/java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:1098)
        ... 4 more

Поскольку исключение выше немного запутно из за модулей Java 9+ приведу исключение на JRE 8

Exception in thread "main" java.lang.IllegalAccessException: no such method: TestedClass.getDefault()TestedClass/invokeStatic
        at java.lang.invoke.MemberName.makeAccessException(MemberName.java:867)
        at java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:1003)
        at java.lang.invoke.MethodHandles$Lookup.resolveOrFail(MethodHandles.java:1386)
        at java.lang.invoke.MethodHandles$Lookup.findStatic(MethodHandles.java:780)
        at Main.method(Main.java:18)
        at Main.main(Main.java:11)
Caused by: java.lang.LinkageError: loader constraint violation: when resolving method "TestedClass.getDefault()LTestedClass;" the class loader (instance of <bootloader>) of the current class, java/lang/Object, and the class loader (instance of DefineClassLoader) for the method's defining class, TestedClass, have different Class objects for the type TestedClass used in the signature
        at java.lang.invoke.MethodHandleNatives.resolve(Native Method)
        at java.lang.invoke.MemberName$Factory.resolve(MemberName.java:975)
        at java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:1000)
        ... 4 more

Что происходит: при каждом вызове метода создается новый ClassLoader, читаются байты класса из файла, класс дефайнится и с помощью MethodHandles я пытаюсь вызвать необходимый мне статический метод
Первый раз проходит успешно - JVM загружает класс впервые и никаких конфликтов это не вызывает
Второй раз ошибка, которой быть не должно. Класслоадер, созданный на предыдущем этапе по идее никак не должен влиять на работу текущего, так как и у первого, и у второго класслоадера родитель SystemClassLoader. Перечитав документацию по classloader так и не могу понять почему такое возникает и как это исправить
Сам defineClass как можно видеть по логу работает без ошибок - проблемы только с вызовом этого метода через MethodHandles. UPD: Использование ещё одного класслоадера(с другим именем класса) не решило проблему


Ответы (0 шт):