https://github.com/danielfernandez/test-dynamic-class-loading
Test repository for a weird class loading behaviour
https://github.com/danielfernandez/test-dynamic-class-loading
Last synced: about 1 year ago
JSON representation
Test repository for a weird class loading behaviour
- Host: GitHub
- URL: https://github.com/danielfernandez/test-dynamic-class-loading
- Owner: danielfernandez
- Created: 2017-05-04T19:43:22.000Z (about 9 years ago)
- Default Branch: master
- Last Pushed: 2017-05-05T20:48:31.000Z (about 9 years ago)
- Last Synced: 2025-01-30T19:49:05.626Z (over 1 year ago)
- Language: Java
- Size: 8.79 KB
- Stars: 0
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.markdown
Awesome Lists containing this project
README
# Test for unexpected behaviour in JVMs dynamic class loading
StackOverflow ticket (including solution): http://stackoverflow.com/questions/43792289/unexpected-behaviour-in-jvm-class-loading-classnotfoundexception-before-the-cla/43793110
Tested with **Java 1.8.0_131**.
This test consists of three artifacts:
* A library called `libone` containing a class called `ParentClassFromLibOne`.
* A library called `libtwo` containing a class called `ParentClassFromLibTwo`, which extends from
`ParentClassFromLibOne`. This library has a (`compile`-scope) dependency on `libone`.
* An application module, with classes `DynamicClassLoadingAppOK` and
`DynamicClassLoadingAppKO` showing how a change in the type of a method
parameter changes the result from the expected behaviour for dynamic
class loading to an unexpected one. This module has a (`compile`-scope)
dependency on `libone` and a (`provided`-scope) dependency on `libtwo`.
Code of `ParentClassFromLibOne`:
```java
public class ParentClassFromLibOne {
public String message() {
return "Message from Parent class at LibOne";
}
}
```
Code of `ChildClassFromLibTwo`:
```java
public class ChildClassFromLibTwo extends ParentClassFromLibOne {
@Override
public String message() {
return "Message from Child class at LibTwo";
}
}
```
Code of the *app* class in which the behaviour is as expected
and the `System.out.println` call at the end is executed:
```java
public class DynamicClassLoadingAppOK {
/*
* THIS VERSION WORKS OK, BECAUSE showMessage RECEIVES THE CHILD CLASS AS A PARAMETER
*/
// If this method received ParentClassFromLibOne, we would have a ClassNotFoundException
private static void showMessage(final ChildClassFromLibTwo 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 is displayed perfecty fine... as expected.");
}
}
```
Code of the *app* class in which the behaviour obtained is
unexpected and the `System.out.println` call at the end is
never executed (a `ClassNotFoundException` is thrown instead).
Note the only difference is the type of the parameter of the
`showMessage(...)` method.
```java
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 :(");
}
}
```
### How to test
First install the two libraries:
```
$ cd libone
$ mvn clean compile install
$ cd ..
$ cd libtwo
$ mvn clean compile install
$ cd ..
```
Then compile and execute the app:
```
$ cd app
$ mvn clean compile
$ mvn exec:java -Dexec.mainClass=com.github.danielfernandez.testdynamicclassloading.app.DynamicClassLoadingAppOK
$ mvn exec:java -Dexec.mainClass=com.github.danielfernandez.testdynamicclassloading.app.DynamicClassLoadingAppKO
```
The first app class executes fine, the second one throws:
```
java.lang.NoClassDefFoundError: com/github/danielfernandez/testdynamicclassloading/libtwo/ChildClassFromLibTwo
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
at java.lang.Class.privateGetMethodRecursive(Class.java:3048)
at java.lang.Class.getMethod0(Class.java:3018)
at java.lang.Class.getMethod(Class.java:1784)
at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:281)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.ClassNotFoundException: com.github.danielfernandez.testdynamicclassloading.libtwo.ChildClassFromLibTwo
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 7 more
```
Note a `ClassNotFoundException` is actually thrown in both cases, but in the `OK` one it happens when the
`ChildClassFromLibTwo` is loaded when a new instance of such class is created, so it is correctly caught
by the `catch (Throwable t)` block and execution can go on.
Nevertheless, in the `KO` class the `ClassNotFoundException` is thrown **before executing `main()`**, apparently when the
`DynamicClassLoadingAppKO` class itself is loaded, and therefore outside of the `try...catch`, so no code is
executed at all.