0

I want to get the names of all the public methods (void return type and no arguments) of a class1 which is dependent on some other class2. I am loading class through UrlClassLoader. Now when i am calling getDeclaredMethods, it is throwing NoClassDefFoundError caused by ClassNotFoundException.

I am having 3 mvn modules as

  1. SampleClassLoader: Using it to get the methods of class of Module1.
  2. Module1: Its class using the reference to classes of Module2. And has a dependency of Module2 in its pom.xml also.
  3. Module2

The whole module structure looks like: Project Structure

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

Module1Class1.java

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

Module1Class2.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();
        }

    }
}

Now, When Running the SampleClassLoader for class Module1Class1 prints

claas1Fun

But when running for class Module1Class2 it is giving NoClassDefFoundError as:

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

I am having two questions here that is:

  1. When using try catch, why it is giving error?
  2. If the class1 is already loaded at classLoader.loadClass then why getDeclaredMethods method need to load dependent classes?
Aayush Jain
  • 183
  • 1
  • 11
  • Are you saying the only difference between `Module1Class1` and `Module1Class2` is the `try/catch`, and only the second one throws a NCDFE? – Kayaman Sep 20 '19 at 12:24
  • yes, that is the only difference. – Aayush Jain Sep 23 '19 at 08:01
  • `loadClass` will not perform all steps to make a class usable. As elaborated in [this answer](https://stackoverflow.com/a/34263422/2711488), we have to differentiate between loading, linking, verifying, and the class initialization. The `loadClass` will perform the loading and definitely not the initialization, whereas the other steps may get performed then or at some later time. The `try … catch` makes the difference between a branch free code and a method with branches, requiring a stackmap table. This may have an impact on the verifier. However, I can not reproduce your result… – Holger Sep 23 '19 at 17:16
  • So it would be helpful to know which compiler/version has been used and which runtime version. – Holger Sep 23 '19 at 17:20
  • [This answer](https://stackoverflow.com/a/52703533/2711488) also addresses why `loadClass` may return successfully while a `NoClassDefFoundError` may happen at a later time. – Holger Sep 23 '19 at 17:26

1 Answers1

0

Concerning the try-catch issue, the point is that java.lang.NoClassDefFoundError is not an Exception, is an Error which is a more severe kind of Throwable.

Errors are, generally speaking, unrecoverable (Like OutOfMemoryError or StackOverflowError, ...), so they are seldom catched.

If you want to catch NoClassDefFoundError you should add catch(NoClassDefFoundError e) to your try

minus
  • 2,646
  • 15
  • 18
  • 1
    My question is why the NoClassDefError is coming? Because of the error i am unable to get the method name. – Aayush Jain Sep 20 '19 at 12:08
  • Because module1 is compiled using module2, but module2 is not in classpath at that moment – minus Sep 20 '19 at 12:56
  • If the class is already loaded at line `classLoader.loadClass()` then why reading method name needs to load dependency? When getting the method name how the classloader knows what is written over there inside the method definition.. It should not worry about what is there inside method. Also, why it is working when I am not using try/catch? – Aayush Jain Sep 23 '19 at 08:00