NullPointerException on getting list of ItemStack

Discussion in 'Spigot Plugin Development' started by kristouffe, May 31, 2018.

  1. Hi folks,

    I try to make a little custom inventory plugin.

    Running the /bag command opens an additional inventory. If i close the inventory (InventoryCloseEvent) I save the content of the inventory to the config file. This works fine.
    My problem is when I retype the command. The plugin doesn't seems to be able to load the Inventory due to nullPointerException.

    Code which saves the inventory:
    Code (Text):
        public void onClose(InventoryCloseEvent e){
            if(e.getInventory().getName() == BagPlugin.getPlugin(BagPlugin.class).getConfig().get("label")){
                ItemStack[] inv = e.getInventory().getContents();
                BagPlugin.getPlugin(BagPlugin.class).getConfig().set("inventories." + e.getPlayer().getUniqueId(), inv);
                BagPlugin.getPlugin(BagPlugin.class).saveConfig();
            }
    Code which loads the inventory:
    Code (Text):
    public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
                Player p = (Player) sender;
                Inventory inv = Bukkit.createInventory(p, plugin.getConfig().getInt("rows")*9, plugin.getConfig().getString("label"));

                if(plugin.getConfig().contains("inventories."+p.getUniqueId().toString())){
                    List<ItemStack> invList = (List<ItemStack>) plugin.getConfig().getList("inventories." + p.getUniqueId().toString());
                    ItemStack[] loadedInv = invList.toArray(new ItemStack[0]);
                    inv.setStorageContents(loadedInv);

                }
                p.openInventory(inv);
    }
    Stacktrace:
    [​IMG]

    The first time i issue the command, the inventory opens with every item as it should. The second time it doesn't work anymore and the ConfigurationSection i want isn't recognized as a List anymore...

    If anyone could help :p
     
  2. What is the line that has the error?
     
  3. I guess it's this one

    Code (Text):
    List<ItemStack> invList = (List<ItemStack>) plugin.getConfig().getList("inventories." + p.getUniqueId().toString());
     
  4. Praya

    Benefactor

    - better to make a variable for main class instead of using this method "BagPlugin.getPlugin(BagPlugin.class)" several times
    - you need to check the sender instance of Player
     
    #4 Praya, May 31, 2018
    Last edited: May 31, 2018
  5. my guess is that the npe is getting caused because you're saving it like this
    Code (Text):
    BagPlugin.getPlugin(BagPlugin.class).getConfig().set("inventories." + e.getPlayer().getUniqueId(), inv);
    and loading it like this
    Code (Text):
    List<ItemStack> invList = (List<ItemStack>) plugin.getConfig().getList("inventories." + p.getUniqueId().toString());
    with the thing being that you're saving using
    Code (Text):
    e.getPlayer().getUniqueId()
    and not
    Code (Text):
    e.getPlayer().getUniqueId().toString()
    because here's what happened when i tried saving with both https://prnt.sc/jp278v
    could be something entirely different but it's worth a shot
     
  6. obviously this is not the whole code, and i tested the sender... and the whole thing. this was just to illustrate the problem ^^'
    BTW the ConfigurationFile serialization uses arrays and not lists.

    thanks for trying. :p. I just changed for
    Code (Text):
    e.getPlayer().getUniqueId().toString()
    and it makes no difference. I can't figure out where this NPE comes from.
    The saving seems to work in both ways.

    [​IMG]

    After reload, te reading of the file works THE FIRST TIME, after that it gives me a NPE

    [​IMG]

    when I use the command the second time => NPE and the inventory doesn't open

    [​IMG]

    This makes really no sense to me :/
     
    • Like Like x 1
  7. Can you post your BagCommand Class?
     
  8. Code (Text):
    import static me.kristouffe.bag.utils.Utils.chat;

    public class BagCommand implements CommandExecutor {
        private BagPlugin plugin;

        BagCommand(BagPlugin plugin) {
            this.plugin = plugin;
        }

        @Override
        public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {

            if(!(sender instanceof Player)){
                sender.sendMessage(chat(plugin.getConfig().getString("ONLY_PLAYERS")));
                return true;
            }

                Player p = (Player) sender;
                Inventory inv = Bukkit.createInventory(p, plugin.getConfig().getInt("rows")*9, plugin.getConfig().getString("label"));

                if(plugin.getConfig().contains("inventories."+p.getUniqueId().toString())){
                    List<ItemStack> invList = (List<ItemStack>) plugin.getConfig().getList("inventories." + p.getUniqueId().toString());
                    ItemStack[] loadedInv = invList.toArray(new ItemStack[0]);
                    inv.setStorageContents(loadedInv);

                }
                p.openInventory(inv);

            return true;
        }
    }
     
     
  9. do a for Loop insteadof an Array and try this

    Code (Java):
    for(int i = 0; i < invList.size(); i++) {
      try {
        inv.setItem(i, invList.get(i));
      } catch(NullPointerException e) {}
    }
    p.openInventory(inv);
     
  10. same result. NPE :(
     
  11. Your NPE is probably coming from somewhere else, then. That try catch statement should prevent you from getting any NullPointerExceptions there as long as invList.size() itself isn't null.
     
  12. I just solved it by reloading the config after the saving...

    I don't know why but it works now... i still would like to understand why ^^'

    Code (Text):
        @EventHandler
        public void onClose(InventoryCloseEvent e){
            if(e.getInventory().getName() == BagPlugin.getPlugin(BagPlugin.class).getConfig().get("label")){
                ItemStack[] inv = e.getInventory().getContents();
                plugin.getConfig().set("inventories." + e.getPlayer().getUniqueId().toString(), inv);
                plugin.saveConfig();
                plugin.reloadConfig();
            }
     
    • Like Like x 1
  13. Strahan

    Benefactor

    I'd just change the way you're doing it period. It'd be a little more bulky in code, but more efficient in storage. Instead of dicking with the array like that, just loop over the contents of the inventory and write to the config like inventories.(uuid).(slot # of item) = the itemstack. Then when you load, loop the keys and build the inv. The way you don't end up with tons of null entries in the config, and it avoids all the headaches you are having with having to reload and such.

    Also, be sure you are either validating config input or giving defaults. If, for example, the admin goes to edit the label for the bag and his/her dumb ass ends up having it say "lable: my bag" it'll make your current code shit itself. Always best to assume the end user is a moron and code accordingly.

    Example:

    Code (Text):
    During command processing {
      Get rows and validate they are accurate
      Create inventory object
      Load the configuration section for the user
      If it's not null, loop over the keys
      Get and validate the key as a valid slot number
      Get the item from the config and ensure it isn't null
      Set the item in the inventory at the right slot
      Display inventory
    }

    During inventory close {
      Check if it's the right inventory
      Clear the existing player inventory in config
      Loop over the inv contents and if an entry is not null, set to config
      Save config
    }
     
  14. thanks buddy, i'll give it a try :)