/ ClassCastException and ClassLoader Puzzle ~ Java EE Support Patterns

2.21.2013

ClassCastException and ClassLoader Puzzle

The following question and puzzle will test your knowledge on Java class loaders and more precisely on one of the Java language specifications. It will also help you better troubleshoot problems such as java.lang.NoClassDefFoundError.

I highly suggest that you do not look at the explanation and solution until you review the code and come up with your own explanation.

You can download the Java program source code and binaries (compiled with JDK 1.7) here. In order to run the program, simply use the following command:

<JDK 1.7 HOME>\bin\java -classpath MainProgram.jar org.ph.javaee.training9.ChildFirstCLPuzzle

** Make sure that you also download the 3 JAR files below before you run the program.

  • MainProgram.jar contains the main program along with super class ProgrammingLanguage.
  • ProgrammingLanguage.jar contains the super class ProgrammingLanguage.
  • JavaLanguage.jar contains the implementation class JavaLanguage, which extends ProgrammingLanguage.

Question (puzzle)

Review closely the program source and packaging along with the diagram below reflecting the class loader delegation model used for this program.



Why can’t we cast (ChildFirstCLPuzzle.java @line 53) the Object javaLanguageInstance of type JavaLanguage, into ProgrammingLanguage?

...............................                   
// Finally, cast the object instance into ProgrammingLanguage
/** Question: why is the following code failing with ClassCastException given the fact JavaLanguage is indeed a ProgrammingLanguage?? **/
ProgrammingLanguage programmingLanguage = (ProgrammingLanguage)javaLanguageInstance;

............................... 

Propose a solution to allow the above cast to succeed without changing the original source code. Hint: look again at the class loader delegation model, packaging and diagram.

Answer & solution

The Java program is attempting to demonstrate a Java language specification rule related to class loaders: two classes loaded by different class loaders are considered to be distinct and hence incompatible.

If you review closely the program source, packaging and diagram, you will realize the following facts:

  • Our main program is loaded to the parent class loader e.g. $AppClassLoader.
  • The super class ProgrammingLanguage is also loaded to the parent class loader since it is referenced by our main program at line 53.
  • The implementation class JavaLanguage is loaded to our child class loader e.g. ChildFirstClassLoader which is following a “child first” delegation model.
  • Finally, the super class ProgrammingLanguage is also loaded to our child class loader.

The key point to understand is that the super class is loaded by 2 different class loaders. As per Java language specification, two classes loaded by different class loaders are considered to be distinct and hence incompatible. This means that ProgrammingLanguage loaded from the “child firs” class loader is different and not compatible with ProgrammingLanguage loaded from the parent classloader. This is why the cast attempted at line 53 failed with the error below:

ChildFirstCLPuzzle execution failed with ERROR: java.lang.ClassCastException: org.ph.javaee.training9.JavaLanguage cannot be cast to org.ph.javaee.training9.ProgrammingLanguage

Now how can we fix this problem without actually changing the source code? Well please keep in mind that we are using a “child first” delegation model here. This is why we end up with 2 versions of the same ProgrammingLanguage class. The solution can be visualized as per below.


In order to fix this problem, we can simply ensure that we have only one version of ProgrammingLanguage loaded. Since our main program is referencing ProgrammingLanguage directly, the solution is to remove the ProgrammingLanguage.jar file from the child class loader. This will force the child class loader to look for the class from the parent class loader, problem solved! In order to test the solution, simply remove the ProgrammingLanguage.jar from your testing folder and re-run the program.

I hope you appreciated this puzzle related to “child first” class loader delegation model and class loader rules. This understanding is especially important when you are dealing with complex Java EE deployments involving many class loaders, exposing you to this type of problems at runtime.

Please do not hesitate to post any comment or question on this puzzle.

2 comments:

I am facing the exact same problem but thing is I can't remove child class loader, I am doing some specific work while loading class. Is there is other option I am ok with code changes.

Hi Shekhar, can you please provide me with more details on your problem error maybe? The solution is normally not to remove the child class loader but to refactor / revisit the packaging of your application.

Post a Comment