[SOLVED] HashMaps, fail.

Discussion in 'Plugin Development' started by davejavu, Apr 3, 2012.

Thread Status:
Not open for further replies.
  1. Offline

    davejavu

    Right, so I'm using HashMaps to export a player's location and name when they /sethome. This works all well and good UNTIL the server restarts, at which point I get an error on my 2337th line, which is "if (Homes.containsKey(player.getName().toLowerCase()){ I don't see why this is giving me an error, help?

    full error (open)
    Code:
    2012-04-03 16:48:26 [SEVERE] null
    org.bukkit.command.CommandException: Unhandled exception executing command 'home' in plugin RandomStuff v1.0
        at org.bukkit.command.PluginCommand.execute(PluginCommand.java:42)
        at org.bukkit.command.SimpleCommandMap.dispatch(SimpleCommandMap.java:166)
        at org.bukkit.craftbukkit.CraftServer.dispatchCommand(CraftServer.java:473)
        at net.minecraft.server.NetServerHandler.handleCommand(NetServerHandler.java:821)
        at net.minecraft.server.NetServerHandler.chat(NetServerHandler.java:781)
        at net.minecraft.server.NetServerHandler.a(NetServerHandler.java:764)
        at net.minecraft.server.Packet3Chat.handle(Packet3Chat.java:33)
        at net.minecraft.server.NetworkManager.b(NetworkManager.java:229)
        at net.minecraft.server.NetServerHandler.a(NetServerHandler.java:113)
        at net.minecraft.server.NetworkListenThread.a(NetworkListenThread.java:78)
        at net.minecraft.server.MinecraftServer.w(MinecraftServer.java:554)
        at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:452)
        at net.minecraft.server.ThreadServerApplication.run(SourceFile:490)
    Caused by: java.lang.NullPointerException
        at me.davejavu.RandomStuff.RandomStuffCommandExecutor.onCommand(RandomStuffCommandExecutor.java:2337)
        at org.bukkit.command.PluginCommand.execute(PluginCommand.java:40)
        ... 12 more


    Please, can someone help >.>

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 25, 2016
  2. Offline

    comp8nerd4u2

    It's an NPE which means you are trying to access an object, whose reference has been set to null. Right before that line, try:
    Code:
    if (Homes == null) {
         logger.log(Level.SEVERE, "Homes is null! NPE imminent!");
    } else if (player == null) {
         logger.log(Level.SEVERE, "player is null! NPE imminent!");
    }
    
    Also, you shouldn't capitalize "Homes". Instead, do "homes" as the variable, unless Homes is really a class that is being used in a static context. If Homes turns out to be null, then how are you reloading Homes? I would really recommend using ObjectOutputStream and ObjectInputStream on a file stream for saving and loading HashMaps. Try searching in Google for an example on how to do this.
     
  3. Offline

    davejavu

    I'm using OOS and OIS, here's the code of how I do it, and I'll de-capitalize "Homes" then ;D
    Show Spoiler
    load:
    Code:java
    1. public static HashMap<String, Location>loadStr(String path){
    2. try{
    3. Object result = ois.readObject();
    4. return (HashMap<String,Location>)result;
    5. }catch(Exception e){
    6. return null;
    7. }
    8. }

    save:
    Code:java
    1. public static void saveDeaths(HashMap<String, Location> Deaths, String path){
    2. File file = new File("plugins/RandomStuff/data" + File.separator + "Deaths.dat");
    3. new File("plugins/RandomStuff/data").mkdir();
    4. if(!file.exists()){
    5. try {
    6. file.createNewFile();
    7. } catch (IOException e) {
    8. e.printStackTrace();
    9. }
    10. }
    11. try{
    12. oos.writeObject(Warps);
    13. oos.flush();
    14. oos.close();
    15. //Handle I/O exceptions
    16. }catch(Exception e){
    17. e.printStackTrace();
    18. }
    19. }


    comp8nerd4u2 Im confused >.>

    Unsolved still, I need help ;3

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 25, 2016
  4. Offline

    comp8nerd4u2

    In the method "LoadStr", you never close the stream you've opened. In the method "saveDeaths", you only close the stream when the save operation is successful, but never when it has failed. I suggest the following in both cases:
    Code:
    // Saving, but adapt example for loading as well
    // Let's save a Random object
    Random random = new Random();
    File file = new File("plugins/RandomStuff/random.object");
    if (!file.exists()) {
        try {
            file.mkdir();
            file.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
            logger.log(Level.SEVERE, "Failed to save random data. Operation was aborted by JVM. (Security settings???)");
            return;
        }
    }
    ObjectOutputStream oos = null;
    try {
        oos = new ObjectOutputStream(new FileOutputStream(file));
        oos.writeObject(random);
        oos.flush();
    } catch (Exception e) {
        e.printStackTrace();
        // Same thing as above but shouldn't be an security exception but maybe the targeted hard drive is failing???
    } finally {
        if (oos != null) {
            try { oos.close(); } catch (Exception e) {}
        }
    }
    Also, you're saving a variable named "Warps" and in your save method, you pass in a variable named "Deaths". Lol, what is going on here? One final thing, in "LoadStr", you return null if loading was unsuccessful, but do you check for when it returns null, or do you just assume it's never going to return null, because, in that case, that could cause "homes" to be null if it couldn't load it. I suggest you change your method's signature to "public static HashMap<String, Location> loadStr(String path) throws IOException" and then throw the IOException that occurs while loading instead of just returning null. This is optional, but it's good programming practice in general because it forces the programmer to account for that situation.
     
  5. Offline

    davejavu

    Yeah, I noticed that just after I pasted it, I believe I've fixed it though.
    Thanks for the help, I shall try this now...

    comp8nerd4u2 So, is this better?
    Code:java
    1. public static HashMap<String, String> loadStr(String path) throws IOException{
    2. try{
    3. Object result = ois.readObject();
    4. return (HashMap<String,String>)result;
    5. }catch(Exception e){
    6. e.printStackTrace();
    7. return null;
    8. }
    9. }


    comp8nerd4u2 then, when I go to load the HashMaps in onEnable(){}, eclipse tells me to surround it with try/catch, because the signature "throws IOException" ;3
    Code:java
    1. File homefile = new File("plugins/RandomStuff/data" + File.separator + "Homes.dat");
    2. new File("plugins/RandomStuff/data").mkdir();
    3. if(!homefile.exists()){
    4. }else{
    5. RandomStuffCommandExecutor.homes = RandomStuffCommandExecutor.loadLoc("plugins/RandomStuff/data" + File.separator + "Homes.dat");
    6. }

    That's how I load them using the method.

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 25, 2016
  6. Offline

    comp8nerd4u2

    You still did not close the close the stream when you were done with it and you are still returning null, which you might as well get rid of "throws IOException" if you are going to just return null. What I meant was:
    Code:
    ...
    } catch (IOException e) {
        if (ois != null) {
            try { ois.close() } catch (IOException e) {}
        }
        throw e;
    }
    ...
    EDIT: When loading, you don't need to make sure the directory or file exists.

    EDIT 2: Your usage of:
    Code:
    File homefile = new File("plugins/RandomStuff/data" + File.separator + "Homes.dat");
    new File("plugins/RandomStuff/data").mkdir();
    Is really pointless. Instead do:
    Code:
    File homefile = new File("plugins/RandomStuff/data/Homes.dat");
    homefile.getParentFile.mkdirs();
     
  7. Offline

    davejavu

    comp8nerd4u2 I've now got rid of the return null, then added the code above - here's what I've got (for the loadStr())
    Eclipse told me to throw ClassNotFoundException for ois.readObject()
    Code:java
    1. public static HashMap<String, String> loadStr(String path) throws IOException, ClassNotFoundException{
    2. try{
    3. Object result = ois.readObject();
    4. return (HashMap<String,String>)result;
    5. }catch(IOException e){
    6. if (ois != null) {
    7. try { ois.close();
    8. } catch (IOException ee) {}
    9. }
    10. throw e;
    11. }
    12. }


    Then, what do I do in onEnable()?
    Here's what I have:
    Code:java
    1. File homefile = new File("plugins/RandomStuff/data" + File.separator + "Homes.dat");
    2. new File("plugins/RandomStuff/data").mkdir();
    3. if(!homefile.exists()){
    4. }else{
    5. try{
    6. RandomStuffCommandExecutor.homes = RandomStuffCommandExecutor.loadLoc("plugins/RandomStuff/data" + File.separator + "Homes.dat");
    7. }catch(Exception e){
    8. e.printStackTrace();
    9. log.log(Level.SEVERE, "Could not load ban list!");
    10. }
    11. }
     
  8. Offline

    comp8nerd4u2

    Oh sorry, change:
    Code:
    ...
    return (HashMap<String,String>)result;
            }catch(IOException e){
                ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path));
    ...
    to this:
    Code:
    ...
    return (HashMap<String,String>)result;
            }catch(Exception e){
                ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path));
    ...
    And then change the end of your method's signature to "throws Exception". It should work fine. Also, why are you calling "RandomStuffCommandExecutor.homes = RandomStuffCommandExecutor.loadLoc("plugins/RandomStuff/data" + File.separator + "Homes.dat");"? Is loadLoc supposed to be loadStr???
     
  9. Offline

    davejavu

    comp8nerd4u2 Did all that, exported, still returned as null
     
  10. Offline

    comp8nerd4u2

    Are you sure "loadLoc" is "loadStr" :/
     
  11. Offline

    davejavu

    oh wait, I didnt do that bit two posts up, I'll do it in an hour, I need to go for a bit
    Thanks so far :)

    And, loadStr is for the HashMaps with <String, String> wheres loadLoc is for HashMaps with <String, Location>. The homes HashMap is <String (player name), Location>.

    -snip-

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 25, 2016
  12. Offline

    comp8nerd4u2

    Lol you marked it solved, so i'm guessing that you figured out that you needed to initialize homes if it couldn't load.
     
  13. Offline

    davejavu

    Nope - I realised that I'd completely mucked up the load and save methods as I'd made like 5, so I had a look at the plugin tutorial, and used their method which, instead of only saving a certain object, could save any, so now I only need 1 save and load method rather than 5 or 6. :p
     
  14. Offline

    comp8nerd4u2

    But to solve the NPE you posted in your last post, change the following in your onEnable() to this:
    Code:
    // Your other code in onEnable
    ...
    try{
        RandomStuffCommandExecutor.homes = RandomStuffCommandExecutor.loadLoc("plugins/RandomStuff/data" + File.separator + "Homes.dat");
    }catch(Exception e){
        e.printStackTrace();
        log.log(Level.WARNING, "Could not load ban list!");
        // You could put this line here or initialize it in a static context. I don't really care but you'll get NPE's until you make sure it's initialized.
        RandomStuffCommandExecutor.homes = new HashMap<String, Location>();
    }
    ...
    // The rest of your code
    Lol unless you make sure homes is initialized, you'll keep getting that NPE.

    EDIT: You should use Level.WARNING for non critical messages.
     
  15. Offline

    davejavu

    It won't need to load from homes until a player types /home, at which point it asks if it contains the players key. If it doesnt, it will return false and send the player a message. It will be initialized as soon as the player types /sethome, at which point it will save the players location to a file for later use.
     
  16. Offline

    comp8nerd4u2

    Just to make sure, if, for example, i joined your server and the file doesn't exist and i had the permission to use your plugin's commands and I just typed /home straight off the bat, it won't generate an NPE because it couldn't load the HashMap object from a non-existant or empty file, right? I need to make sure because i've seen it happen where people i've already helped make another thread that they are having the same problem.
     
Thread Status:
Not open for further replies.

Share This Page