Konstantin Ignatyev e-mail Do not work harder, work smarter!
Home
Articles
Presentations
Projects
Personal
Annoyances

 

 

When Java Classloaders drive me crazy (2002).

It looks like Classloader architecture becomes more and more an issue during Java development. There is a live example: a web application has a factory that returns an interface (DAO). Implementation of the interface is varying of course. At this point I have following implementations:

•  In-memory DAO simulator;

•  Castor based persistence;


Client has ability to set a particular DAO implementation at runtime. That is a moment when things go wrong: this application works fine with "In-memory DAO", but when client calls a function to set "Castor-JDO DAO" we experience a quite weird behavior:

•  client cannot get list of objects;

•  it can create a new object;

•  cannot see that new object;

•  Was able to search and get a list of those;

•  When a new object that match search criteria was created, that search stopped working;

No need to say that "Castor JDO DAO" seems working fine. At least when the same client uses that "Service" object directly and does everything locally, then everything works just fine.

That behavior is Web container dependent and Resin behaves a bit differently than Tomcat. But regardless of container the problem pops up in SOAP publisher, which suddenly cannot find mapping for a class. It looks extremely confusing, because DAO factory returns the same interface, and the interface declares very particular return type.

When we set "In-memory DAO", then everything works fine again.

Wow! That is really confusing:

Service deals with interface -> interface returns MyObject class. Fair enough, isn't it?

Lets look closely:

•  When MyObject comes out of "In-memory DAO" then SOAP publisher CAN find mapping and marshal/unmarshal an instance of the class (MyOblect) to/from XML.

•  When MyObject comes out of "Castor-JDO DAO" " then SOAP publisher CANNOT find mapping and marshal/unmarshal an instance of the class (MyOblect) to/from XML.

Oops!

I did not mention exact stack trace message yet because it container dependent (looks like JVM dependent too) and it says "ClassCastException" or "Mapping for clazz was not found" or " [java] Caused by: java.lang.IllegalArgumentException: argument type mismatch

[java] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

[java] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAcces

sorImpl.java:39) "

So. "The same" class might or might NOT be recognized depends on "something". That something is " classloader ". That is that, what I consider to be a weak spot in Java: implicit relationship between "Language" and "JVM", implementation clashes with language semantic.

Language semantic:

if ( obj instanceof MyClass ) dictates return true if instance " obj " is a sort of MyClass.

Runtime implementation does not guarantee that. Even if " obj " is an instance of MyClass that " instanceof " will return FALSE if the " obj " was loaded by a different classloader.

I understand some security reasons for that classloader dependence, but that "implicit" and inconsistent behavior creates more and more problems for J2EE development.

In this particular application there is only one location of MyClass.class file: under WEB-INF/classes .

"In-memory DAO" instantiates MyClass directly by calling new MyClass() , when "Castor-JDO" does that via reflection. Somehow "Castor-JDO" seems using different classloader.

Wow! One application, one source location. code does not work.

Another inconsistency: if we assume that implicit Classloader dependency is OK, then how about "interface" behavior. The same interface returns " different " classes.

I consider this behavior as very confusing and troublesome.

What bothers me most: that inconsistent behavior depends on JVM/OS/WebContainer combination. Sometimes there is ClassCastException, and sometimes classes get casted and only Axis code, that tries to find an appropriate mapping for an object of class MyClass cannot make it because MyClass.class != obj.getClass() .

In a debugger it looks terrible: object of class MyClass is not an instance of class MyClass. .

http://www.theserverside.com/resources/article.jsp?l=ClassLoading

http://www.jadcentral.com/newscentral/feature.jsp?feature_ID=51

Happy development and debugging!!!

 

© 2001 - 2006 Konstantin Ignatyev