Два класса загружены ClassLoader, они не могут вызывать друг друга - PullRequest
0 голосов
/ 09 января 2019

Предположим, у вас есть два класса Java

package package1;

public class SampleClass1 {

    public SampleClass1() {

        System.out.println("Sample Class Loaded and Called");
    }
}

package package1.package2;

import package1.SampleClass1;

public class SampleClass2 {

    public SampleClass2() {

        new SampleClass1();
        System.out.println("Sample Class 2 Loaded and Called");
    }
}

и загрузить два класса с помощью ClassLoader примерно так:

package load;

public class LoadClassFromByteData extends ClassLoader {

    private byte[] classByteData;

    public LoadClassFromByteData(byte[] classByteData) {
        this.classByteData = classByteData;
    }

    public Class<?> getLoadedClass(String className) {

        return defineClass(className, classByteData, 0, classByteData.length);
    }
}

//

Class<?> loadedClass1 = loadClassFromByteData.getLoadedClass("package1.SampleClass1");
Class<?> loadedClass2 = loadClassFromByteData.getLoadedClass("package1.package2.SampleClass2");

когда я вызываю конструктор SampleClass1 так:

Constructor<?> mainCons1 = loadedClass1.getConstructor();
mainCons1.newInstance();

успешно печатает «Sample Class Loaded and Called», но когда я вызываю конструктор loadClass2, загружаемый из байтовых данных SampleClass2, у меня появляется ошибка вроде:

Constructor<?> mainCons2 = loadedClass2.getConstructor();
mainCons2.newInstance();

// И да, сначала я загружаю SampleClass1, затем загружаю SampleClass2, наконец, я вызываю конструктор SampleClass2.

Exception in thread "main" java.lang.reflect.InvocationTargetException
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
    at db.recorder.deneme.main(deneme.java:48)
Caused by: java.lang.NoClassDefFoundError: package1/SampleClass1
    at package1.package2.SampleClass2.<init>(SampleClass2.java:9)
    ... 5 more
Caused by: java.lang.ClassNotFoundException: package1.SampleClass1
    at java.base/java.lang.ClassLoader.findClass(ClassLoader.java:718)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:588)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
    ... 6 more

Я хочу добавить эту информацию, байтовые данные двух классов хранятся в БД, и я получаю байтовые данные классов из БД. На самом деле, в проекте нет ни одного пакета с именем package1 или package2!

Спасибо за ваши ответы и советы.

1 Ответ

0 голосов
/ 09 января 2019

Вам необходимо предоставить родительский загрузчик классов.

   public static class LoadClassFromByteData extends ClassLoader {

        final ConcurrentHashMap<String, Class<?>> definedClassesByName = new ConcurrentHashMap<>();

        LoadClassFromByteData(ClassLoader parent) {
            super(parent);
        }

        public Class<?> getLoadedClass(String className, byte[] classAsBytes) {

            return this.definedClassesByName.computeIfAbsent(className,
                    cn -> defineClass(cn, classAsBytes, 0, classAsBytes.length));
        }
    }

    @Test
    public void test() throws IOException, InstantiationException, IllegalAccessException {

        final byte[] sampleClass1Bytes = Files.readAllBytes(SAMPLE_CLASS1_CLASS_FILE_PATH);
        final byte[] sampleClass2Bytes = Files.readAllBytes(SAMPLE_CLASS2_CLASS_FILE_PATH);

        final ClassLoader contextClassLoader = Thread.currentThread()
            .getContextClassLoader();
        final LoadClassFromByteData loadClassFromByteData = new LoadClassFromByteData(contextClassLoader);
        final Class<?> sampleClass1 = loadClassFromByteData.getLoadedClass("package1.SampleClass1", sampleClass1Bytes);
        final Object sampleClass1Instance = sampleClass1.newInstance();
        final Class<
            ?> sampleClass2 = loadClassFromByteData.getLoadedClass("package1.package2.SampleClass2", sampleClass2Bytes);
        final Object newInstance = sampleClass2.newInstance();
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...