ClassNotFound for jar within project?

Discussion in 'Plugin Development' started by Malikk, Jun 21, 2012.

  1. Offline

    Malikk

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    Hey everybody,

    I'm having an issue hooking in the API of another plugin. It has custom exceptions, so in order to keep this as a soft depend, I've included the plugin I'm hooking within my own jar.

    I've set the build path correctly and double checked my classpath, and everything seems to be correct. Everything compiles correctly, as well, but the plugin won't load up due to a ClassNotFoundException.

    How is this possible? The jar is directly included in my project and I've double checked that I am, in fact, exporting the folder its in as well.

    I am really stumped here.

    Thanks in advance.
  2. Offline

    Digi

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    Ehh you don't need to do that... just use:
    Code:
    if(Bukkit.getPluginManager().getPlugin("YourHookedPlugin") instanceof YourHookedPluginMainClass)
    {
        // plugin exists, use it.
    }
    If that's not it... you should show some code and the stacktrace itself, which usually clears stuff up.
  3. Offline

    Malikk

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    I understand getting the running instance of a plugin, that's not the issue. The issue is the custom exceptions. They throw ClassNotFoundExceptions when the class they are in is instantiated.

    Code:
    try {
                allowed = api.getFlagValue(player, "EpicGlass", sregion);
            } catch (FlagNotFoundException e) {
                plugin.log("FlagNotFound");
            } catch (InvalidFlagException e) {
                plugin.log("InvalidFlag");
            } catch (InvalidRegionException e) {
                plugin.log("Invalid Region");
            }
    
    These exception classes are all referenced and the build path is set from a jar which is included in my own jar, yet they still throw ClassNotFoundExceptions.

    I don't think it's going to tell you anything at all, but here's the error.


    01:21:36 [SEVERE] Could not load 'plugins/EpicGlass.jar' in folder 'plugins'
    org.bukkit.plugin.InvalidPluginException: java.lang.NoClassDefFoundError: us/twoguys/shield/exceptions/FlagNotFoundException
    at org.bukkit.plugin.java.JavaPluginLoader.loadPlugin(JavaPluginLoader.java:149)
    at org.bukkit.plugin.SimplePluginManager.loadPlugin(SimplePluginManager.java:305)
    at org.bukkit.plugin.SimplePluginManager.loadPlugins(SimplePluginManager.java:230)
    at org.bukkit.craftbukkit.CraftServer.loadPlugins(CraftServer.java:213)
    at org.bukkit.craftbukkit.CraftServer.reload(CraftServer.java:550)
    at org.bukkit.Bukkit.reload(Bukkit.java:182)
    at org.bukkit.command.defaults.ReloadCommand.execute(ReloadCommand.java:22)
    at org.bukkit.command.SimpleCommandMap.dispatch(SimpleCommandMap.java:166)
    at org.bukkit.craftbukkit.CraftServer.dispatchCommand(CraftServer.java:479)
    at org.bukkit.craftbukkit.CraftServer.dispatchServerCommand(CraftServer.java:475)
    at net.minecraft.server.MinecraftServer.b(MinecraftServer.java:612)
    at net.minecraft.server.MinecraftServer.w(MinecraftServer.java:581)
    at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:459)
    at net.minecraft.server.ThreadServerApplication.run(SourceFile:492)
    Caused by: java.lang.NoClassDefFoundError: us/twoguys/shield/exceptions/FlagNotFoundException
    at me.jordan.epicGlass.EpicGlass.<init>(EpicGlass.java:30)
    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:513)
    at org.bukkit.plugin.java.JavaPluginLoader.loadPlugin(JavaPluginLoader.java:145)
    ... 13 more
    Caused by: java.lang.ClassNotFoundException: us.twoguys.shield.exceptions.FlagNotFoundException
    at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
    at org.bukkit.plugin.java.PluginClassLoader.findClass(PluginClassLoader.java:41)
    at org.bukkit.plugin.java.PluginClassLoader.findClass(PluginClassLoader.java:29)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:315)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:250)
    at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:398)
    ... 19 more
  4. Offline

    Njol

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    Please remove everything that is not your code from your jar, this will just cause issues.
    Try to move everything that depends on the other plugin into onEnable(). Some of Bukkit's methods are not available when the plugin is instantiated.
  5. Offline

    Malikk

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    The issue is that if the server doesn't have the hooked plugin, these classes can't be found and throw errors, so I'm attempting to add the jar to my jar so that even if the plugin isn't found, I can still load the classes without any issues.

    I realize that I could essentially quarantine these exceptions in their own class, but I really don't want to do that. It's very clean the way it is, and I'm simply trying to figure out how to load those classes from an included jar. I can't figure out why it doesn't work during runtime, because everything compiles correctly and the build path is correct as well.

    This has nothing to do with Bukkit at all. This has to do with class references that can't be found upon class instantiation.

    This post has been edited 1 time. It was last edited by Malikk Jun 21, 2012.
  6. Offline

    Njol

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    Maybe in order for your plugin to catch those exceptions their classes have to be loaded, but as long as the other plugin doesn't throw one they are not loaded. In this case you can try to load them with Class.forName("...") or ask the other plugin's author to load the exception classes when his plugin is instantiated.
  7. Offline

    Malikk

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    There's no issue when the server has both plugins, only when it doesn't have the hooked one.
  8. Offline

    desht

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    The only way around this is to isolate all references to those exceptions into their own class(es) in your plugin, and only instantiate (or call static methods of) those classes if you know you've successfully hooked the plugin.

    I do something similar with WorldEdit in my ChessCraft plugin: see https://github.com/desht/ChessCraft...me/desht/chesscraft/blocks/TerrainBackup.java. Note that the WorldEdit API can throw a com.sk89q.worldedit.data.DataException and code in my TerrainBackup class catches that. As long as I ensure that all TerrainBackup methods are only called when WorldEdit is loaded, there's no problem. E.g. see https://github.com/desht/ChessCraft...java/me/desht/chesscraft/chess/BoardView.java line 467.
  9. Offline

    Njol

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    So Java tries to load the exception's classes even though their catch clause is never reached?
    In this case I can think of 2 solutions: Either put everything that handles the custom exceptions into a class you're sure you never load if the other plugin is not enabled, or catch a generic Exception and then use instanceof to find what kind of exception was caught.

    edit: ninja'ed

    This post has been edited 1 time. It was last edited by Njol Jun 22, 2012.
  10. Offline

    desht

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    Yeah, seems that way. The JVM will need the exception class(es) loaded to be able to match against them, regardless of whether or not the catch clause is actually hit.
  11. Offline

    Malikk

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    I realize that I could easily just isolate everything, but why can't I just add the jar I'm referencing to my own? I can't figure out why it can't find those exception classes at runtime, even tho they are in my own project.
  12. Offline

    Malikk

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    bump.

    I'm sure this is a simple problem. All I'm trying to do is reference a class from a jar in my project, but it's not finding the classes at runtime.
  13. Offline

    Njol

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    I guess the jar inside your jar is not in your classpath
  14. Offline

    Malikk

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    The classpath is correct
  15. Offline

    Njol

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    Do you mean the .classpath generated by Eclipse (or aother GUI?) is correct? This file is only used by Eclipse and ignored by the JVM.
    It's the runtime classpath that's important which can be e.g. set in the command line with -cp, though I don't think it's possible to specify a jar inside a jar. You'll have to load the jar yourself, but this is less desirable that simply moving all code that catches the custom exceptions in a separate class.
    Malikk likes this.
  16. Offline

    ferrybig

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    yo u cant load classes from a jar inside a jar
  17. Offline

    Malikk

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    I guess I'm just not understanding why this isn't possible.

    But thanks for the input, everyone.
  18. Offline

    Malikk

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    I'm going to go ahead and just isolate the references, but for future reference, is it possible for to copy classes from a jar and load them myself? without rewriting or copying, etc.

    Like, in this case, would it be possible to just pull out those exception classes so that I can use them?

    Sorry if this is a dumb question, it's not something I have a lot of experience with.

    This post has been edited 1 time. It was last edited by Malikk Jun 24, 2012.
  19. Offline

    Sagacious_Zed Bukkit Docs

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Minecraft account:
    MCUSERNAME
    Yes, it is possible to shade the contents of a jar, the easiest way i find is to do it with maven, however this itself will cause problems if you intend for another plugin to exist most of the time.

    This post has been edited 1 time. It was last edited by Sagacious_Zed Jun 24, 2012.

Share This Page