Linkage Error

Discussion in 'Spigot Plugin Development' started by Qruet, Aug 7, 2018.

  1. It's not necessarily a critical issue, however it is something I would like to address. Upon restarting my plugin, everything works very well, without a single error, however using the reload command, or at least the reload command used by plugman and the plugin will begin to malfunction and spew this error:
    Code (Text):
     Caused by: java.lang.LinkageError: loader constraint violation: when resolving method "net.pyrix.mc.pvm.arena.ArenaPlayer.getArena()Lnet/pyrix/mc/pvm/arena/Arena;" the class loader (instance of org/bukkit/plugin/java/PluginClassLoader) of the current class, net/pyrix/mc/pvm/commands/general/ArenaJoinCmd, and the class loader (instance of org/bukkit/plugin/java/PluginClassLoader) for the method's defining class, net/pyrix/mc/pvm/arena/ArenaPlayer, have different Class objects for the type net/pyrix/mc/pvm/arena/Arena used in the signature
    It's always the same class, Arena. To my understanding the arena class that I am returning from a method is not sharing the same signature of the original, then again that shouldn't return an error so perhaps I'm missing something? By restarting the server, this issue never occurs/disappears. I understand reloading a plugin can present issues therefore it is discouraged, however it makes me uncomfortable that such an error would even exist after reloading, making me come to the conclusion that a portion of my code is poorly written and should be addressed.
     
    #1 Qruet, Aug 7, 2018
    Last edited: Aug 7, 2018
  2. The instance if the Arena class seems to be the sane after reload.
    Why don't you drop the instance (onDisable, if needed) and create a new one when the plugin gets enabled (onEnable) again?
    I guess you check onEnable if there already is an instance and if so, you keep it?
    I woudn't do that since a reload should reload everything.
     
  3. I actually have a remove function in each arena class that I iterate through in a loop and call when the plugin disables. It then resets the arena and removes itself from the list. I create a new instance when the plugin is enabled (onEnable) from a list of files for each arena, each containing the unique properties for each arena.
     
  4. From the error ArenaJoinCmd seems to be the object that is still in memory after reloading
     
  5. Nope, I am not storing that object and the error appears to be coming from retrieving the Arena class from the ArenaPlayer class. Other command classes that are handled similarly to ArenaJoinCmd that do not use the ArenaPlayer class in any way do not result in any errors, such as the alias command without any args that simply pulls up a list of commands. PlayerQuitCmd class for example does return a similar error, since it as well uses the ArenaPlayer class and tries to get the Arena. The arena that the player is in isn't stored in ArenaPlayer but instead calls a method in a Utility class that goes through a list of stored arenas to see if that player is in the arena. This list is cleared on disable therefore I can't think of a single place where the Arena classes are being stored.
     
  6. Since this issue appears to be a bit more complex then I originally thought it was, I'll provide more information since I am aware that the given information provided may limit the amount of help that I can hope to get.
    Code (Text):
    [00:04:13] [Server thread/INFO]: geekles issued server command: /plugman reload PlayerVSMob
    [00:04:13] [Server thread/INFO]: [PlayerVSMob] Disabling PlayerVSMob v0.2.15-ALPHA
    [00:04:13] [Server thread/INFO]: [PlayerVSMob] Enabling PlayerVSMob v0.2.15-ALPHA
    [00:04:13] [Server thread/INFO]: [PlayerVSMob] Setting up economy...
    [00:04:13] [Server thread/INFO]: [PlayerVSMob] Successfully setup economy.
    [00:04:13] [Server thread/INFO]: [PlayerVSMob] Registering custom entities...
    [00:04:13] [Server thread/INFO]: [PlayerVSMob] Entities successfully registered!
    [00:04:13] [Server thread/INFO]: [PlayerVSMob] Setting up commands...
    [00:04:13] [Server thread/INFO]: [PlayerVSMob] Commands successfully setup!
    [00:04:13] [Server thread/INFO]: [PlayerVSMob] Setting up colored teams...
    [00:04:13] [Server thread/INFO]: [PlayerVSMob] Successfully setup!
    [00:04:13] [Server thread/INFO]: [PlayerVSMob] Registering listeners...
    [00:04:13] [Server thread/INFO]: [PlayerVSMob] Listeners successfully registered!
    [00:04:13] [Server thread/INFO]: [PlayerVSMob] Retrieving data from database...
    [00:04:13] [Server thread/INFO]: [PlayerVSMob] Successfully enabled!
    [00:04:17] [Server thread/INFO]: geekles issued server command: /pvm join underground
    [00:04:17] [Server thread/ERROR]: null
    org.bukkit.command.CommandException: Unhandled exception executing command 'pvm' in plugin PlayerVSMob v0.2.15-ALPHA
        at org.bukkit.command.PluginCommand.execute(PluginCommand.java:46) ~[custom.jar:git-Spigot-2086bb0-2f3ed3b]
        at org.bukkit.command.SimpleCommandMap.dispatch(SimpleCommandMap.java:141) ~[custom.jar:git-Spigot-2086bb0-2f3ed3b]
        at org.bukkit.craftbukkit.v1_12_R1.CraftServer.dispatchCommand(CraftServer.java:648) ~[custom.jar:git-Spigot-2086bb0-2f3ed3b]
        at net.minecraft.server.v1_12_R1.PlayerConnection.handleCommand(PlayerConnection.java:1397) [custom.jar:git-Spigot-2086bb0-2f3ed3b]
        at net.minecraft.server.v1_12_R1.PlayerConnection.a(PlayerConnection.java:1232) [custom.jar:git-Spigot-2086bb0-2f3ed3b]
        at net.minecraft.server.v1_12_R1.PacketPlayInChat.a(PacketPlayInChat.java:45) [custom.jar:git-Spigot-2086bb0-2f3ed3b]
        at net.minecraft.server.v1_12_R1.PacketPlayInChat.a(PacketPlayInChat.java:1) [custom.jar:git-Spigot-2086bb0-2f3ed3b]
        at net.minecraft.server.v1_12_R1.PlayerConnectionUtils$1.run(SourceFile:13) [custom.jar:git-Spigot-2086bb0-2f3ed3b]
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [?:1.8.0_161]
        at java.util.concurrent.FutureTask.run(FutureTask.java:266) [?:1.8.0_161]
        at net.minecraft.server.v1_12_R1.SystemUtils.a(SourceFile:46) [custom.jar:git-Spigot-2086bb0-2f3ed3b]
        at net.minecraft.server.v1_12_R1.MinecraftServer.D(MinecraftServer.java:748) [custom.jar:git-Spigot-2086bb0-2f3ed3b]
        at net.minecraft.server.v1_12_R1.DedicatedServer.D(DedicatedServer.java:406) [custom.jar:git-Spigot-2086bb0-2f3ed3b]
        at net.minecraft.server.v1_12_R1.MinecraftServer.C(MinecraftServer.java:679) [custom.jar:git-Spigot-2086bb0-2f3ed3b]
        at net.minecraft.server.v1_12_R1.MinecraftServer.run(MinecraftServer.java:577) [custom.jar:git-Spigot-2086bb0-2f3ed3b]
        at java.lang.Thread.run(Thread.java:748) [?:1.8.0_161]
    Caused by: java.lang.LinkageError: loader constraint violation: when resolving method "net.pyrix.mc.pvm.arena.ArenaPlayer.getArena()Lnet/pyrix/mc/pvm/arena/Arena;" the class loader (instance of org/bukkit/plugin/java/PluginClassLoader) of the current class, net/pyrix/mc/pvm/commands/general/ArenaJoinCmd, and the class loader (instance of org/bukkit/plugin/java/PluginClassLoader) for the method's defining class, net/pyrix/mc/pvm/arena/ArenaPlayer, have different Class objects for the type net/pyrix/mc/pvm/arena/Arena used in the signature
        at net.pyrix.mc.pvm.commands.general.ArenaJoinCmd.onCommand(ArenaJoinCmd.java:43) ~[?:?]
        at net.pyrix.mc.pvm.commands.PVMCommandManager.onCommand(PVMCommandManager.java:75) ~[?:?]
        at org.bukkit.command.PluginCommand.execute(PluginCommand.java:44) ~[custom.jar:git-Spigot-2086bb0-2f3ed3b]

    Code (Text):
    package net.pyrix.mc.pvm.commands.general;

    import net.pyrix.mc.pvm.PVM;
    import net.pyrix.mc.pvm.arena.Arena;
    import net.pyrix.mc.pvm.arena.ArenaPlayer;
    import net.pyrix.mc.pvm.commands.PVMCmd;
    import net.pyrix.mc.pvm.commands.PVMCommandManager;
    import net.pyrix.mc.pvm.utils.ArenaUtils;
    import net.pyrix.mc.pvm.utils.PlayerCalculator;
    import net.pyrix.mc.pvm.utils.T;
    import net.pyrix.mc.pvm.utils.ToolBox;
    import org.bukkit.entity.Player;

    public class ArenaJoinCmd extends PVMCmd {

        private final String permission = "pyrix.pvm.join";
        private final String description = "Join an arena";

        public ArenaJoinCmd() {
            PVMCommandManager.registerCommand(this);
        }

        @Override
        public String[] getArgs() {
            return new String[]{"join/j", ""};
        }

        @Override
        public String getPermission() {
            return permission;
        }

        @Override
        public String getDescription() {
            return description;
        }

        @Override
        public void onCommand(Player player, String[] args) {
            String arena_name = args[0];
            Arena arena = ArenaUtils.getArenaFromName(arena_name);
            ArenaPlayer aplayer = ArenaPlayer.getArenaPlayerFromPlayer(player);
            Arena player_arena = aplayer.getArena();
            if (arena != null && player_arena == null) {
                double price = PlayerCalculator.calculatePlayer(player);
                if (PVM.econ.getBalance(player) >= price) {
                    if (arena.getLobby().addPlayer(player)) {
                        PVM.econ.withdrawPlayer(player, price);
                        player.sendMessage(T.c("&aCost of admission to enter the arena was &2$" + ToolBox.RoundTo2Decimals(price) + "&a. You can get your money back if you decide to " +
                                "quit right now, &o/playervsmob quit"));
                    } else {
                        player.sendMessage(T.c("&c&oUnable to join, the arena is most likely being used at the moment, please try again later."));
                    }
                } else {
                    player.sendMessage(T.c("&cYou don't have enough money to pay for admission &4&o($" + ToolBox.RoundTo2Decimals(price) + ")&c to enter the arena! Note the cost of admission is determined " +
                            "by the items in your inventory."));
                }
            } else if (player_arena != null) {
                if (player_arena.equals(arena)) {
                    player.sendMessage(T.c("&cYou are already in that arena. Try leaving with &4/pvm quit&c and joining again with &4/pvm join " + arena_name + "&C."));
                } else {
                    player.sendMessage(T.c("&cYou are already in an arena. Try leaving with &4/pvm quit&c and joining again with &4/pvm join " + arena_name + "&c."));
                }
            } else {
                player.sendMessage(T.c("&cArena, &4&o" + arena_name + " &cdoes not exist!"));
            }
        }
    }