[Solved][Adv. Java] Read external jar with reference to plugin

Discussion in 'Plugin Development' started by dadaemon, Jan 23, 2012.

Thread Status:
Not open for further replies.
  1. Yeah, I know. What is this for strangely worded question?! I'm sorry but I could not find a better way to describe the problem I've gotten myself into.

    I've done a lot of searching but can't find the solution to my problem. I will try and be as clear as possible and hopefully you'll get what I mean. (For the examples below I've removed simple stuff like finding the files and adding the imports etc.)

    I'm trying to make a plugin that reads external jar files to extend the plugin itself.
    Code:
                    String lcStr = fileName.toLowerCase() + "." + fileName;
                    URLClassLoader cl = null;
                    try {
                        cl = URLClassLoader.newInstance(new URL[]{file.toURI().toURL()});
                        try {
                            Class loadedClass = cl.loadClass(lcStr);
                            for(Constructor c:this.loadedClass.getConstructors()) {             
                                plugin.log.debug("Constructor: " + c.toGenericString());
                            }
                        } catch (ClassNotFoundException ex) {
                            plugin.log.severe("Error in external jar. Can't find class '" + lcStr + "'", ex);
                        }
                    } catch (MalformedURLException ex) {
                        plugin.log.severe("Error in external jar.", ex);
                    }
    
    It looks simple enough right? Load the class and check all constructors and print them out.
    Here is the constructor of the plugin (found in the directory Bukkit\plugins\PName\extra\ )
    Code:
        public Extra_Location() {
            this.type = "Extra Location";
        }
    
    All goes well. I can find the constructor and use it to initialize the new jar.
    Here comes the problem!
    I want the external jar to reference the plugin itself. I tought it would be as easy as making a new constructor but with a argument to my plugin. So I added a new constructor.
    Code:
        public Extra_Location(MyPlugin plugin) {
            this.type = "Extra Location";
            this.plugin = plugin;
        }
    
    This is where the plugin breaks. It can't find the class defenition to MyPlugin anymore. Strange as it is being called from MyPlugin.
    Things I've done to solve this:
    • Add a class-path to the manifest.mf file of the external file (tried every know path, even directly to MyPlugin.jar itself!)
    • Added MyPlugin as a library to the external file
    • Added full path to the plugin in manifest.mf. This results in not able to find the class in the external file.
    I hope you Bukkit/Java guru's out there could help me! I'm pretty stuck on this problem right now :(
    Many thanks!

    Edit: Problem solved! Thanks to nisovin .
    This is the only piece that needs to be changed from
    Code:
    cl = URLClassLoader.newInstance(new URL[]{file.toURI().toURL()});
    
    to
    Code:
    cl = URLClassLoader.newInstance(new URL[]{file.toURI().toURL()}, this.getClass().getClassLoader());
    
    This piece of code works if your putting this in your main class. Else you have to change this to a reference to your plugin.
     
  2. Offline

    ItsHarry

    This is known as a "Module" system btw

    Anyhow, maybe you instead of putting an argument in the constructor, you could simply make a method which has the main class as argument.

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 23, 2016
  3. If it could find MyPlugin then I could reference it in the external file. But that's the whole problem. If I put any reference to it in the external file it would error in a NoClassDefFoundError for MyPlugin.

    Update: I've probably found a way to implement the class-path in the manifest.mf but this resolves into a new error. When I add the full path to my plugin (on windows: D:\\Bukkit\\Plugins\\MyPlugin.jar) in the Class-Path section of the manifest.mf it gives me a "ClassNotFoundException" to the class of the external file where this normally won't. I will update the opening post.
     
  4. Offline

    Don Redhorse

    you could try using Plugin instead of your plugin class, would that help?

    did you look into how bukkit is doing it?
     
  5. Offline

    nisovin

    When you create a URLClassLoader, you can pass in your current class loader as a second parameter. You need to do this for it all to work properly.

    Code:
    cl = URLClassLoader.newInstance(new URL[]{file.toURI().toURL()}, getClassLoader());
    
     
    tyzoid, desht and dadaemon like this.
  6. You sir deserves the helpful post of the week award!

    I've changed the opening post to reflect the change. (Only one extra variable... sigh!)
     
Thread Status:
Not open for further replies.

Share This Page