• We’re currently investigating an issue related to the forum theme and styling that is impacting page layout and visual formatting. The problem has been identified, and we are actively working on a resolution. There is no impact to user data or functionality, this is strictly a front-end display issue. We’ll post an update once the fix has been deployed. Thanks for your patience while we get this sorted.

Java Class Loading

I get a cast exception on line 25?!

try{
Plugin plugin = (Plugin) plugins.get(i).newInstance();
}catch (Exception e){
System.out.println(e);
client.eventLog.logError("Unable to initialize plugin", e.getMessage());
}


I am casting a known class which IMPLEMENTS 'Plugin' - You can cast to an interface can't you?
 
I believe you're trying to cast a Class (which happens to define Plugin), not an actual Plugin instance.
 
I can create an instance of class in question and cast it to the plugin interface no problem

It appears to not want to work if I am loading the class from a file stored on my harddrive? 🙁

P.S thanks for the quick answer
 
Sorry, I was a little too eager to answer, it looks like =)
Edit: Can't you do a system.out of the plugins.get(i).newInstance().getClass() to see what it is tossing your way?
Edit: Any chance the Plugin interface within your source isn't resolving to the same definition that the binary classes were compiled against? Maybe run an equality test against "Plugin.getClass() == plugins.get(i).getInterfaces[0]"? (Or something similar)
 
Try using more parens to enclose exactly what you're trying to cast so the compiler doesn't get confused with false assumptions.
 
I've tried:

try{
Object obj = plugins.get(i).newInstance();
Plugin plugin = (Plugin) obj;
}catch (Exception e){
System.out.println(e);
client.eventLog.logError("Unable to initialize plugin", e.getMessage());
}

But no luck 🙁
 
Originally posted by: Ned Flanders
I've tried:

try{
Object obj = plugins.get(i).newInstance();
Plugin plugin = (Plugin) obj;
}catch (Exception e){
System.out.println(e);
client.eventLog.logError("Unable to initialize plugin", e.getMessage());
}

But no luck 🙁

Try:

Object obj = plugins.get(i);
Plugin plugin = ((Plugin)obj).newInstance();
 
Originally posted by: MrChad
Try:

Object obj = plugins.get(i);
Plugin plugin = ((Plugin)obj).newInstance();
plugins is a Vector of Classes, not Plugins so that won't work.

Ned, you don't happen to have the Plugin interface in your plugin folder do you? It almost sounds like you have two versions of its bytecode being loaded, one by your URLClassLoader and one by whatever loaded your PluginLoader (presumably the jvm one, whatever it's called).

I think diegoalcatraz was on the right track as far as testing class equality. When you've got the plugin Class, try looping over its interfaces and printing out what they are. Also print out the data about each interface's ClassLoader and make sure it matches with what you expect for the ClassLoader of Plugin, as it's referenced in your code.
 
No the Plugin.class interface is stored in ./client/ whereas the plugin folder is ./client/plugins/

I'll get right on printing out the interfaces are you suggested: Good idea 🙂

Thanks everyone.
 
OK - The interfaces listed: client.Plugin

Just as expected. Could this have something to do with the package a plugin is in? I guess it wouldn't matter if I could load a class without having to know it's name, but I don't think that is possible. Thus I have to get the class name from the file name - If it was part of a package I'd have to know the full class name e.g. client.plugin.APlugin

So far I have only been able to load a class when I give the plugin directory as "././" - it fails with 'NoClassDefFound' for client/Plugin if I try (what seems to me the better choice) "/client/plugins" - Im sure this could be part of the problem ?
 
Originally posted by: diegoalcatraz

Edit: Any chance the Plugin interface within your source isn't resolving to the same definition that the binary classes were compiled against? Maybe run an equality test against "Plugin.getClass() == plugins.get(i).getInterfaces[0]"? (Or something similar)

Opps - Didn't see this as it was an edit - I'll give it a go, thanks.
 
Originally posted by: Ned Flanders
OK - The interfaces listed: client.Plugin
Yep. As seems consistent with your discovery just above, just because a class has the same name doesn't mean it's the same class. A class is only uniquely defined by the combination of its name its classloader. I don't see any nice identification methods on ClassLoader but the toString() method should give you a way to see if your Plugin.class.getClassLoader() is different from plugins.get(i).getInterfaces[0].getClassLoader().

Also, try diego's test with a .equals() rather than ==, just in case.
 
Interfaces
client.Plugin

Equals
false

Class loader for

Plugin Class: java.net.URLClassLoader@1b5998f
Plugin Interface from loaded class: java.net.URLClassLoader@181497d
 
Ok, so here's my crack-brained theory, not sure if it's right:
-when your plugin loader starts executing, the Plugin interface has not yet been referenced so no classloader has bothered to find it
-you come to the point where you tell your classloader to pick up the class file from disk
-it does so and discovers that it also needs to know about the Plugin interface in order to properly link the plugin bytecode
-it asks its parent classloader (in this case, the jvm classloader) if it knows about Plugin, answer is 'no'
-your classloader then looks around for the Plugin bytecode and finds it on the same classpath as the actual plugin implementation so it loads it
-now your code tries to cast the new implementation
-it now needs to have a definition of the Plugin interface but the jvm classloader doesn't have one (classes are not passed up the classloader hierarchy)
-so it looks on its own classpath, finds Plugin and loads it
-you now have two different versions

The solution? Make sure the Plugin interface is loaded and linked before you do stuff with your own classloader. Try declaring a Plugin as a member of your PluginLoader class, even if you never use it. It will need to be loaded and linked before any code gets executed and when your classloader asks its parent for the Plugin class, it will be there.

If that works, it's a bit of a dirty hack but at least it would shed some light on the situation. In the long run, it's probably wiser not to have the Plugin interface in the same folder hierarchy as the Plugin implementations.
 
Grrr 🙁

So - The plugin interface is stored at ./client/
Edit: The plugins are now stored at /plugins

I now get a lovely error:
java.lang.NoClassDefFoundError: Test (wrong name: plugins/Test)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:620)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:124)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:260)
at java.net.URLClassLoader.access$100(URLClassLoader.java:56)
at java.net.URLClassLoader$1.run(URLClassLoader.java:195)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
at client.util.PluginLoader.loadPlugins(PluginLoader.java:34)
at client.util.PluginLoader.<init>(PluginLoader.java:22)
at client.gui.Client.<init>(Client.java:48)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:494)
at bluej.runtime.ExecServer$3.run(ExecServer.java:871)

 
Originally posted by: Ned Flanders
Grrr 🙁

So - The plugin interface is stored at ./client/
The plugins are not stored at /plugins

I now get a lovely error:
java.lang.NoClassDefFoundError: Test (wrong name: plugins/Test)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:620)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:124)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:260)
at java.net.URLClassLoader.access$100(URLClassLoader.java:56)
at java.net.URLClassLoader$1.run(URLClassLoader.java:195)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
at client.util.PluginLoader.loadPlugins(PluginLoader.java:34)
at client.util.PluginLoader.<init>(PluginLoader.java:22)
at client.gui.Client.<init>(Client.java:48)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:494)
at bluej.runtime.ExecServer$3.run(ExecServer.java:871)
That doesn't appear to have anything to do with the Plugin interface, you're not even getting that far. Can you provide more details on this test?
 
Back
Top