4

I've created a simple webapp using Spring & Jetty, and am creating a hello world JDO test using DataNucleus & DB4O.

I can persist a class no problem, but when I go to query for the class I get a ClassCastException, can't cast a.b.c.MyClass to a.b.c.MyClass.

When I examine the classloader of the original object I created, it's [WebAppClassLoader@1592226291], naturally it's springs WebApp classloader.

I am performing both the persist operation and query operation in the same servlet method, when I re-read the object from the DB with a simple query I get back a set of a.b.c.MyClass objects from the DB, but the classloader is [sun.misc.Launcher$AppClassLoader@5acac268], thus the exception.

Following the DataNucleus docs here http://www.datanucleus.org/extensions/classloader_resolver.html

...the JDO2 class-loading mechanism utilises 3 class loaders
* When creating the PersistenceManagerFactory you can specify a class loader. This is used first if specified
* The second class loader to try is the class loader for the current thread.
* The third class loader to try is the class loader for the PMF context.

I covered the first two options documented, and verified that the classloader is the WebAppClassLoader in the Servlet with these debug steps in the servlet:

Thread.currentThread().getContextClassLoader().toString()
((JDOPersistenceManagerFactory)pm.getPersistenceManagerFactory()).getPrimaryClassLoader().toString()

Both yield [WebAppClassLoader@1592226291] as the classloader.

I'm not sure where I'm going wrong here.

Cœur
  • 37,241
  • 25
  • 195
  • 267
David Parks
  • 30,789
  • 47
  • 185
  • 328
  • Have you checked the class-loaders of the object and the class in the cast? object.getClass().getClassLoader().equals(MyClass.class.getClassLoader())? Such an exception is 99% a class-loader issue. – Gamlor Oct 25 '10 at 14:31
  • I think I'm seeing it now. It's a Jetty/Spring issue, Spring allows me to define some components under the application context (system class loader) and others in the servlet contexts (web app class loader provided by jetty). You should post that as an answer. – David Parks Oct 25 '10 at 14:56

1 Answers1

1

My earlier comment as an answer:

This exception indicates that it is a class loader issue. Compare the class-loader of the object and the class you're using for the cast.

ClassLoader loaderOfObject = theObject.getClass().getClassLoader();
ClassLoader loaderOfLocalClass = MyClass.getClassLoader();
// have to be the same.
assert loaderOfObject.equals(loaderOfLocalClass);

Btw: If db4o is using the wrong class-loader. You can change that by configuring the class-loader explicit.

    EmbeddedConfiguration configuration = Db4oEmbedded.newConfiguration();
    JdkReflector reflector = new JdkReflector(Thread.currentThread().getContextClassLoader());
    configuration.common().reflectWith(reflector);
    ObjectContainer container = Db4oEmbedded.openFile(configuration, "database.db4o");

When a single class-loader isn't enough: You can also pass a instance of the db4o-interface JdkLoader instead of a class-loader. In there you can implement any class-lookup method. For example to look up in multiple class loaders.

Marek Sebera
  • 39,650
  • 37
  • 158
  • 244
Gamlor
  • 12,978
  • 7
  • 43
  • 70