Replace Class.forName(...) with ClassLoader.loadClass(...) to avoid ClassCastException when running inside an OSGi container
Description
Environment
Attachments
Activity

Former user September 15, 2011 at 6:55 PM
Attachment PluginManager.java.patch has been added with description: http://java.net/jira/secure/attachment/26756/PluginManager.java.patch

Nick Lothian January 5, 2009 at 8:47 PM
Committed the following change (different to the patch):
ClassLoader classLoader =
Thread.currentThread().getContextClassLoader();
List classes = new ArrayList();
+ boolean useLoadClass =
Boolean.valueOf(System.getProperty("rome.pluginmanager.useloadclass",
"false")).booleanValue();
for (int i = 0; i <_propertyValues.length; i+) {- Class mClass = Class.forName(_propertyValues[i], true, classLoader); Class mClass = (useLoadClass ? classLoader.loadClass(_propertyValues[i]) : Class.forName(_propertyValues[i], true, classLoader)); classes.add(mClass); }
Class[] array = new Class[classes.size()];
The code will now use loadClass if the system property "rome.pluginmanager.useloadclass" is set to "true"

Nick Lothian January 5, 2009 at 8:45 PM
Will commit based on Alejandro comment.

Nick Lothian January 5, 2009 at 8:40 PM
From Alejandro Abdelnur on the dev list:
What the link explains it kinds of make sense. However, as Nick pointed out, I'm
not sure what would it break out there if we do that change.
Still, if the change of forName() to loadClass() would be done, the patch is not
correct. the patch does:
+ try
+ {+ mClass =PluginManager.class.getClassLoader().loadClass(_propertyValues[i]);+ }
+ catch (ClassNotFoundException ex)
+ {+ mClass = classLoader.loadClass(_propertyValues[i]);+ }
when, IMO, it should do just:
+ mClass = classLoader.loadClass(_propertyValues[i]);
Because extensions may be overriden in another classloader. Example, rome core
in tomcat/lib and extensions in a web-app.
I would agree to have this behavior added (to work in OSGi containers) if it is
activated by a system property and the default is the current behavior.

Nick Lothian January 4, 2009 at 10:47 PM
I haven't tested this, and I'm not a classloading expert by any means, but this
patch looks problematic to me.
The big problem I see is that the current code uses the ContextClassloader for
the current thread (ClassLoader classLoader =
Thread.currentThread().getContextClassLoader() while the new code uses the
classloader for the plugin manager. Changing that will cause problems in some
classloading environments.
The second problem is that one of the comments on the referenced post passes
advice from Sun saying "Applications should basically never call
Classloader.loadClass(). It may appear to work but it is often subtly wrong, can
be a source of latent bugs, and is almost never the best choice. They should
instead call Class.forName() using the 3 parameter version that takes a specific
Classloader instance". I think I'd be happy to ignore this advice if we can
resolve the first issue.
Details
Assignee
ROME Jira LeadROME Jira LeadReporter
ozgweiozgweiFix versions
Affects versions
Priority
Major
Details
Details
Assignee

Reporter

Please see
http://blog.bjhargrave.com/2007/09/classforname-caches-defined-class-in.html for
explanation.
The problem I encountered is that the client of my OSGi bundle also uses rome
and has already loaded those classes defined in rome.properties. When the
PluginManager in my bundle tries to load these classes, the typecast fails.
Replacing Class.forName in Pluginmanager with ClassLoader.loadClass fixes the
problem.