Menu

#33 ClassCastException in KeyFactory$Generator.create

open
nobody
None
5
2010-05-04
2010-05-04
Chris Nokes
No

The following exception occurs when the Enhancer class is linked:

Caused by: java.lang.ClassCastException: net.sf.cglib.proxy.Enhancer$EnhancerKey$$KeyFactoryByCGLIB$$7fb24d72 incompatible with net.sf.cglib.core.KeyFactory
at net.sf.cglib.core.KeyFactory$Generator.create(KeyFactory.java:145)
at net.sf.cglib.core.KeyFactory.create(KeyFactory.java:117)
at net.sf.cglib.core.KeyFactory.create(KeyFactory.java:108)
at net.sf.cglib.core.KeyFactory.create(KeyFactory.java:104)
at net.sf.cglib.proxy.Enhancer.<clinit>(Enhancer.java:69)
at java.lang.J9VMInternals.initializeImpl(Native Method)
at java.lang.J9VMInternals.initialize(J9VMInternals.java:194)

The root cause is related to the creation of the KeyFactory. When AbstractClassGenerator generates classes, it first attempts to load the class instead of generating:
if (attemptLoad) {
try {
gen = loader.loadClass(getClassName());
} catch (ClassNotFoundException e) {
// ignore
}
}
if (gen == null) {
byte[] b = strategy.generate(this);
String className = ClassNameReader.getClassName(new ClassReader(b));
getClassNameCache(loader).add(className);
gen = ReflectUtils.defineClass(className, b, loader);
}

When running in an environment with PARENT_LAST classloading and CGLIB exists in both the parent and child classloaders, the child classloader will fail if the parent classloader has already loaded a class for the generated class name.

Recommend to update the above try block to:

Class cl = loader.loadClass(getClassName());
if(loader().equals(cl.getClassLoader) {
// Only use the existing class if it’s classloader
// is the classloader used to store the generated class
gen = cl;
}

Discussion