Hey, I have a problem when trying to abstract a command. I have a HashMap in my Main class containing all of my commands. All of the commands are registered in the constructors of the SubClasses. Could someone please explain why I'm getting a nullpointerexception? Thanks! Abstract class Code (Text): public abstract class BansCommand implements CommandExecutor { String commandName; String permission; boolean canConsoleUse; private Main plugin; public BansCommand(final String commandName, final String permission, final boolean canConsoleUse){ this.commandName = commandName; this.permission = permission; this.canConsoleUse = canConsoleUse; plugin.getCommand(commandName).setExecutor(this); plugin.commands.put(commandName, this); } public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args){ if(!plugin.commands.containsKey(commandLabel)){ return true; } if(!sender.hasPermission(permission)){ sender.sendMessage(colorize("&cYou do not have permission.")); return true; } if(!canConsoleUse && !(sender instanceof Player)){ sender.sendMessage(colorize("&cOnly players can execute this command.")); return true; } execute(sender, args); return true; } public abstract void execute(final CommandSender sender, final String[] args); public String colorize(String message){ return ChatColor.translateAlternateColorCodes('&', message); } } Main class Code (Text): public class Main extends JavaPlugin { FileConfiguration config; File cfile; FileConfiguration bans; File bfile; public static HashMap<String, BansCommand> commands; public void onEnable(){ cfile = new File(getDataFolder(), "config.yml"); config = YamlConfiguration.loadConfiguration(cfile); config.options().copyDefaults(true); save(cfile, config); bfile = new File(getDataFolder(), "bans.yml"); bans = YamlConfiguration.loadConfiguration(bfile); bans.options().copyDefaults(true); save(bfile, bans); commands = new HashMap<String, BansCommand>(); registerCommands(); this.getServer().getPluginManager().registerEvents(new JoinListener(), this); } public void registerCommands(){ new TestCommand(); } public void save(File file, FileConfiguration config){ try{ config.save(file); }catch(IOException e){ getLogger().warning("Could not save " + file.getName()); } } public FileConfiguration getConfig(){ return config; } public FileConfiguration getBans() { return bans; } } TestCommand subclass Code (Text): public class TestCommand extends BansCommand { public TestCommand(){ super("test", "test.test", true); } public void execute(CommandSender sender, String[] args){ sender.sendMessage("You ran the test command"); } } Stack trace: http://pastebin.com/guZCAGbf
I am not sure (I can't look at the stacktrace, pastebin is blocked at my office) but in your abstract command class, plugin never gets assigned a value and thus is null and throwing your NPE
Here is the stack trace, could you elaborate more? Code (Text): [01:59:11 ERROR]: Error occurred while enabling Bans v1.0 (Is it up to date?) java.lang.NullPointerException at com.unbinding.bans.BansCommand.<init>(BansCommand.java:22) ~[?:?] at com.unbinding.bans.cmds.TestCommand.<init>(TestCommand.java:12) ~[?:?] at com.unbinding.bans.Main.registerCommands(Main.java:40) ~[?:?] at com.unbinding.bans.Main.onEnable(Main.java:35) ~[?:?] at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlugin.java:321) ~[spigot-1.8.8.jar:git-Spigot-db6de12-18fbb24] at org.bukkit.plugin.java.JavaPluginLoader.enablePlugin(JavaPluginLoader.java:340) [spigot-1.8.8.jar:git-Spigot-db6de12-18fbb24] at org.bukkit.plugin.SimplePluginManager.enablePlugin(SimplePluginManager.java:405) [spigot-1.8.8.jar:git-Spigot-db6de12-18fbb24] at org.bukkit.craftbukkit.v1_8_R3.CraftServer.loadPlugin(CraftServer.java:357) [spigot-1.8.8.jar:git-Spigot-db6de12-18fbb24] at org.bukkit.craftbukkit.v1_8_R3.CraftServer.enablePlugins(CraftServer.java:317) [spigot-1.8.8.jar:git-Spigot-db6de12-18fbb24] at org.bukkit.craftbukkit.v1_8_R3.CraftServer.reload(CraftServer.java:741) [spigot-1.8.8.jar:git-Spigot-db6de12-18fbb24] at org.bukkit.Bukkit.reload(Bukkit.java:535) [spigot-1.8.8.jar:git-Spigot-db6de12-18fbb24] at org.bukkit.command.defaults.ReloadCommand.execute(ReloadCommand.java:25) [spigot-1.8.8.jar:git-Spigot-db6de12-18fbb24] at org.bukkit.command.SimpleCommandMap.dispatch(SimpleCommandMap.java:141) [spigot-1.8.8.jar:git-Spigot-db6de12-18fbb24] at org.bukkit.craftbukkit.v1_8_R3.CraftServer.dispatchCommand(CraftServer.java:641) [spigot-1.8.8.jar:git-Spigot-db6de12-18fbb24] at org.bukkit.craftbukkit.v1_8_R3.CraftServer.dispatchServerCommand(CraftServer.java:627) [spigot-1.8.8.jar:git-Spigot-db6de12-18fbb24] at net.minecraft.server.v1_8_R3.DedicatedServer.aO(DedicatedServer.java:412) [spigot-1.8.8.jar:git-Spigot-db6de12-18fbb24] at net.minecraft.server.v1_8_R3.DedicatedServer.B(DedicatedServer.java:375) [spigot-1.8.8.jar:git-Spigot-db6de12-18fbb24] at net.minecraft.server.v1_8_R3.MinecraftServer.A(MinecraftServer.java:654) [spigot-1.8.8.jar:git-Spigot-db6de12-18fbb24] at net.minecraft.server.v1_8_R3.MinecraftServer.run(MinecraftServer.java:557) [spigot-1.8.8.jar:git-Spigot-db6de12-18fbb24] at java.lang.Thread.run(Unknown Source) [?:1.8.0_91]
you need to give it your plugin instance. I would recommend using 'dependency injection' for that. Add a new parameter to your BansCommand constructor so that you can give a value to 'plugin'. Your test command constructor needs to have that parameter too, to pass it over to super. Then, when you register your command, add 'this' as a paramterer to the constructor call
Constructor from abstract class. I added the main value, how do I put it in the subcommand class for super? Code (Text): public BansCommand(Main main, final String commandName, final String permission, final boolean canConsoleUse){ this.commandName = commandName; this.permission = permission; this.canConsoleUse = canConsoleUse; plugin.getCommand(commandName).setExecutor(this); plugin.commands.put(commandName, this); this.plugin = main; }
you need to change the constructor there too Code (Text): public TestCommand(Main main){ super(main,"test", "test.test", true); } then you can call it with new TestCommand(this) in your main class