Class.getDeclaredMethods выдает NoClassDefFoundError для метода класса без аргументов и возвращаемого типа void

Я хочу получить имена всех общедоступных методов (пустой тип возвращаемого значения и без аргументов) класса1, который зависит от какого-либо другого класса2. Я загружаю класс через UrlClassLoader. Теперь, когда я вызываю getDeclaredMethods, он выдает NoClassDefFoundError, вызванный ClassNotFoundException.

У меня есть 3 модуля mvn как

  1. SampleClassLoader: использование для получения методов класса Module1.
  2. Module1: его класс, использующий ссылку на классы Module2. И также имеет зависимость от Module2 в своем pom.xml.
  3. Модуль2

Вся структура модуля выглядит следующим образом: Структура проекта

ClassLoadingTest
|----- Module1
|       |--- pom.xml
|       |--- src/main/java/
|       |               |--- com.classloadingtest.module1
|       |                           |
|       |                           |--- Module1Class1.java
|       |                           |--- Module1Class2.java
|       
|----- Module2
|       |--- pom.xml
|       |--- src/main/java/
|       |               |--- com.classloadingtest.module2
|       |                           |
|       |                           |--- Module2Class.java
|       
|----- SampleClassLoader
|       |--- pom.xml
|       |--- src/main/java/
|       |               |--- com.classloadingtest.sampleClassLoader
|       |                           |
|       |                           |--- SampleClassLoader.java

Модуль1Класс1.java

public class Module1Class1 {
    public void claas1Fun() {
        Module2Class module2ClassObj = new Module2Class();
        module2ClassObj.module2Fun();
    }
}

Модуль1Класс2.java

public class Module1Class2 {

    public void class2Fun(){
        try {
            Module2Class module2ClassObj = new Module2Class();
            module2ClassObj.module2Fun();
        } catch(Exception e ){

        }
    }
}

Module2Class.java

public class Module2Class {

    public void module2Fun(){

    }
}

SampleClassLoader.java

public class SampleClassLoader {
    public static void main(String[] args) {

        try {

            URL mainSourceClassPathURL = new URL("file:" + System.getProperty("user.dir") + "/ClassLoadingTest/Module1/target/classes/");

            URL[] urls = { mainSourceClassPathURL};
            ClassLoader classLoader = URLClassLoader.newInstance(urls);

            Class<?> testCaseClass = classLoader.loadClass("com.classloadingtest.module1.Module1Class1");
            Method method[] = testCaseClass.getDeclaredMethods();

            for (int i = 0 ; i < method.length ; i++) {
                System.out.println(method[i].getName());
            }

        } catch (Exception e){
            e.printStackTrace();
        }

    }
}

Теперь при запуске SampleClassLoader для класса Module1Class1 печатает

claas1Fun

Но при работе для класса Module1Class2 он выдает NoClassDefFoundError как:

Exception in thread "main" java.lang.NoClassDefFoundError: com/classloadingtest/module2/Module2Class
    at java.lang.Class.getDeclaredMethods0(Native Method)
    at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
    at java.lang.Class.getDeclaredMethods(Class.java:1975)
    at com.classloadingtest.sampleClassLoader.SampleClassLoader.main(SampleClassLoader.java:26)
Caused by: java.lang.ClassNotFoundException: com.classloadingtest.module2.Module2Class
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at java.net.FactoryURLClassLoader.loadClass(URLClassLoader.java:814)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    ... 4 more

У меня есть два вопроса, а именно:

  1. Почему при использовании try catch выдает ошибку?
  2. Если class1 уже загружен в classLoader.loadClass, то почему метод getDeclaredMethods должен загружать зависимые классы?

person Aayush Jain    schedule 20.09.2019    source источник
comment
Вы хотите сказать, что единственная разница между Module1Class1 и Module1Class2 заключается в try/catch, и только второй выдает NCDFE?   -  person Kayaman    schedule 20.09.2019
comment
да, это единственная разница.   -  person Aayush Jain    schedule 23.09.2019
comment
loadClass не будет выполнять все шаги, чтобы сделать класс пригодным для использования. Как указано в этом ответе, мы должны различать загрузку, связывание, проверку и инициализацию класса. loadClass выполнит загрузку, а не инициализацию, в то время как другие шаги могут быть выполнены позже или позже. try … catch делает разницу между кодом без ветвей и методом с ветвями, требующим таблицы стековой карты. Это может повлиять на верификатор. Однако я не могу воспроизвести ваш результат…   -  person Holger    schedule 23.09.2019
comment
Поэтому было бы полезно знать, какой компилятор/версия использовалась и какая версия среды выполнения.   -  person Holger    schedule 23.09.2019
comment
Этот ответ также объясняет, почему loadClass может успешно вернуться, а NoClassDefFoundError может произойти позже.   -  person Holger    schedule 23.09.2019


Ответы (1)


Что касается проблемы с попыткой поймать, то дело в том, что java.lang.NoClassDefFoundError — это не Exception, а Error, который является более серьезной разновидностью Throwable.

Ошибки, вообще говоря, неисправимы (например, OutOfMemoryError или StackOverflowError,...), поэтому их редко обнаруживают.

Если вы хотите поймать NoClassDefFoundError, вы должны добавить catch(NoClassDefFoundError e) к своей попытке

person minus    schedule 20.09.2019
comment
Мой вопрос: почему приходит NoClassDefError? Из-за ошибки я не могу получить имя метода. - person Aayush Jain; 20.09.2019
comment
Поскольку модуль1 скомпилирован с использованием модуля2, но модуль2 в этот момент не находится в пути к классам. - person minus; 20.09.2019
comment
Если класс уже загружен в строке classLoader.loadClass(), то почему чтение имени метода должно загружать зависимость? При получении имени метода, как загрузчик классов узнает, что там написано внутри определения метода. Он не должен беспокоиться о том, что там внутри метода. Кроме того, почему это работает, когда я не использую try/catch? - person Aayush Jain; 23.09.2019