Unexpected behaviour in JVM class loading (ClassNotFoundException before the class is really needed)
classloader, dynamic-class-loaders, java
Solution
OK, the details of why this happens are explained in this Spring Boot ticket [1] which I've been very lucky to be promptly pointed to by Andy Wilkinson. That was definitely a difficult one IMO.
Apparently, what happens in this case is that when the calling class itself is loaded, the verifier kicks in and sees that the `showMessage()` method receives an argument of type `ParentClassFromLibOne`. So far so good, and this would not provoke a `ClassNotFoundException` at this phase even if `ParentClassFromLibOne` was not in the classpath at runtime.
BUT apparently the verifier also scans method code and notes that there is a call in `main()` to that `showMessage()` method. A call that does not pass as an argument a `ParentClassFromLibOne`, but instead an object of a different class: `ChildClassFromLibTwo`.
So it is in this case that the verifier does try to load `ChildClassFromLibTwo` in order to be able to check if it really extends from `ParentClassFromLibOne`.
Interestingly this wouldn't happen if `ParentClassFromLibOne` was an interface, because interfaces are treated as `Object` for assignment.
Also, this does not happen if `showMessage(...)` directly asks for a `ChildClassFromLibTwo` as an argument because in such case the verifier does not need to load the child class to check it is compatible... with itself.
Daniel, I'm voting up your answer but I will not mark it as accepted because I consider it fails at explaining the real reason why this is happening at verify time (it's not the class in the signature of the method that's causing the `ClassNotFoundException`).
[1] https://github.com/spring-projects/spring-boot/issues/8181
Problem
I would need help trying to understand why this is happening to me: Using Java 1.8.0_131, I have a class such as this: ``` public class DynamicClassLoadingAppKO { /* * THIS VERSION DOES NOT WORK, A ClassNotFoundException IS THROWN BEFORE EVEN EXECUTING main() */ // If this method received ChildClassFromLibTwo, everything would work OK! private static void showMessage(final ParentClassFromLibOne obj) { System.out.println(obj.message()); } public static void main(final String[] args) throws Throwable { try { final ChildClassFromLibTwo obj = new ChildClassFromLibTwo(); showMessage(obj); } catch (final Throwable ignored) { // ignored, we just wanted to use it if it was present } System.out.println("This should be displayed, but no :("); } } ``` Two other classes are being used up there: `ParentClassFromLibOne` and `ChildClassFromLibTwo`. The latter extends from the former. There are two external libraries involved: - One library is called `libone` and contains the `ParentClassFromLibOne` class. The application includes this library in the classpath both for compiling and executing. - A second library is called `libtwo` and contains the `ChildClassFromLibTwo` class. The application includes this library in the classpath for compiling, but not for executing. As far as I understand, the Java runtime should try to load the `ChildClassFromLibTwo` (which is not in the classpath at runtime) at this line: ``` final ChildClassFromLibTwo obj = new ChildClassFromLibTwo(); ``` Given this class is not in the classpath, a `ClassNotFoundException` should be thrown, and given this line is inside a `try...catch (Throwable)`, the `System.out.println` line at the end should be executed anyway. However, what I get is the `ClassNotFoundException` thrown when the `DynamicClassLoadingAppKO` itself is loaded, apparently before the `main()` method is executed at all, and therefore not caught by the `try...catch`. What seems more strange to me is that this behaviour disappears and everything works as I would expect if I change the signature of the `showMessage()` method so that instead of receiving an argument of the parent class, it is directly of the child class: ``` /* * THIS VERSION WORKS OK, BECAUSE showMessage RECEIVES THE CHILD CLASS AS A PARAMETER */ private static void showMessage(final ChildClassFromLibTwo obj) { System.out.println(obj.message()); } ``` How is this possible? What am I missing in the way class loading works? For testing convenience, I have created a GitHub repository replicating this behaviour [1]. [1] https://github.com/danielfernandez/test-dynamic-class-loading/tree/20170504