Solved Data of a file deleting every time a reload happens.

Discussion in 'Plugin Development' started by Gonmarte, Apr 10, 2016.

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

    Gonmarte

    Hi,
    I created a project to test this before trying in my "real" project.

    Im trying to save a object inside a yaml file.

    So i created my own file and set the directory.

    Everytime i run the command /dog , it creates a dog called Billy and with the age of 15. I use the ObjectOutPutStream to save this object into my yaml file. Then when i run the command /mydog it will give me back the information of my dog, using the ObjectInPutStream , and i will be able to get the name and age of my dog. The problem is that, if i run the command /dog , it will save the object into a file, but if i do /reload (to reload my server) it will delete the data of my file, and i dont want that because if i try /mydog it wont return anything once the file is clear.

    Here is my Main class - http://pastebin.com/73PXu91f

    Here is my Dog class - http://pastebin.com/P5DmwQGm

    Thank you
     
  2. Hey, first of all, I would use a BufferedWriter instead of an outputStream because they are easier to handle: https://docs.oracle.com/javase/7/docs/api/java/io/BufferedWriter.html

    When you use any writer of any kind, you have t be careful because of you close the BufferedWriter and the BufferedWriter is empty, it will overwrite everything in the file with an empty line (I had that problem several times).

    So before you open and close the BufferedWriter, either make sure that the file does not exist, then create the new file, open the BufferedWriter, write into the writer and then close the BufferedWriter.

    Your other option is to use a BufferedReader, to iterate over every single line in your code and if a line that you need is missing open the BufferedWriter, write everything you need again and close it then!

    I hope I could help you, for further questions just ask me ;)
     
  3. Offline

    Gonmarte

    First of all, thanks for you help.
    I checked if the file exists before the whole process and it it still deleting my file.
    Code:
    package me.gonmarte;
    
    import java.io.*;
    
    import org.bukkit.command.Command;
    import org.bukkit.command.CommandSender;
    import org.bukkit.configuration.InvalidConfigurationException;
    import org.bukkit.configuration.file.FileConfiguration;
    import org.bukkit.configuration.file.YamlConfiguration;
    import org.bukkit.entity.Player;
    import org.bukkit.plugin.java.JavaPlugin;
    
    public class Main extends JavaPlugin{
       
          public File ClansData = new File("plugins/" + File.separator + "Clans", "ClansData.yml");
          public FileConfiguration cd = YamlConfiguration.loadConfiguration(this.ClansData);
         
          // Saving my File
          public void saveFiles() {
                try {
                  this.cd.save(this.ClansData);
                } catch (IOException e) {
                  e.printStackTrace();
                 
                }
              }
         
              //Loading my file
              public void loadFiles() {
                if (this.ClansData.exists()){
                  try {
                     
                    this.cd.load(this.ClansData);
                   
                  }catch(IOException e){
                      e.printStackTrace();
                   
                  } catch (InvalidConfigurationException e) {
                    e.printStackTrace();
                   
                }
                  }
              }
             
        @Override
        public void onEnable() {
            loadFiles();
        }
       
        @Override
        public void onDisable() {
            saveFiles();
        }
       
        @Override
        public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
            if(command.getName().equalsIgnoreCase("dog") && sender instanceof Player){
                Dog myDog = new Dog("Billy" , 15);
               
                if(ClansData.exists()){
                try {
                    ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(ClansData));
                    os.writeObject(myDog);
                    os.close();
                } catch (FileNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
               
                Player p = (Player) sender;
                p.sendMessage("Criaste o teu cao");
                return true;
                }
           
        }else if(command.getName().equalsIgnoreCase("mydog") && sender instanceof Player){
            Player p = (Player) sender;
            if(ClansData.exists()){
                try {
                    ObjectInputStream in = new ObjectInputStream(new FileInputStream(ClansData));
                    Dog dog = (Dog) in.readObject();
                    in.close();
                    p.sendMessage("O teu cao é: " +dog.name + " e a sua idade: " + dog.age);
                } catch (FileNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (ClassNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
           
        }
            return false;
    }
    }
    
     
  4. Hey @Gonmarte , let me show you my class that I wrote for the same purpose you are doing:

    Code:java
    1.  
    2. public class Settings {
    3.  
    4. private File file;
    5. private YamlConfiguration configuration;
    6.  
    7. public Settings(){
    8. File f = new File("plugins/WorldRegeneration");
    9. if(!f.exists()) f.mkdir();
    10.  
    11. file = new File("plugins/WorldRegeneration/Settings.yml");
    12. configuration = YamlConfiguration.loadConfiguration(file);
    13.  
    14. if(!file.exists()){
    15. try {
    16. file.createNewFile();
    17.  
    18. BufferedWriter writer = new BufferedWriter(new FileWriter(file));
    19.  
    20. addComment(writer, "Set to true to allow explosions");
    21. addComment(writer, "Set to false to cancel all explosions");
    22. addLine(writer, "AllowExplosions", true);
    23. addEmptyLine(writer);
    24.  
    25. addComment(writer, "Set the time before the world starts regenerating in ticks (1 second = 20 ticks)");
    26. addLine(writer, "RebuildDelay", 80);
    27. addEmptyLine(writer);
    28.  
    29. addComment(writer, "Set the time between blocks when he world starts regenerating in ticks (1 second = 20 ticks)");
    30. addLine(writer, "BlockDelay", 3);
    31. addEmptyLine(writer);
    32.  
    33. addComment(writer, "Set to true to allow explosion fire");
    34. addComment(writer, "Set to false to stop explosion fire");
    35. addLine(writer, "ExplosionFire", true);
    36. addEmptyLine(writer);
    37.  
    38. addComment(writer, "Set to the maximum radius an explosion can be");
    39. addLine(writer, "MaxExplosionRadius", 5);
    40.  
    41. writer.close();
    42. } catch (IOException e) {
    43. e.printStackTrace();
    44. }
    45. }
    46.  
    47. }
    48.  
    49. public boolean allowExplosions(){
    50. return configuration.getBoolean("AllowExplosions");
    51. }
    52.  
    53. public boolean explosionFire(){
    54. return configuration.getBoolean("ExplosionFire");
    55. }
    56.  
    57. public Integer rebuildDelay(){
    58. return configuration.getInt("RebuildDelay");
    59. }
    60.  
    61. public Integer blockDelay(){
    62. return configuration.getInt("BlockDelay");
    63. }
    64.  
    65. public Integer maxExplosionRadius(){
    66. return configuration.getInt("MaxExplosionRadius");
    67. }
    68.  
    69. public void addComment(BufferedWriter writer, String comment){
    70. try {
    71. writer.write("#" + comment);
    72. writer.newLine();
    73. } catch (IOException e) {
    74. e.printStackTrace();
    75. }
    76. }
    77.  
    78. public void addLine(BufferedWriter writer, String line, Object value){
    79. try {
    80. writer.write(line + ": " + value);
    81. writer.newLine();
    82. } catch (IOException e) {
    83. e.printStackTrace();
    84. }
    85. }
    86.  
    87. public void addEmptyLine(BufferedWriter writer){
    88. try {
    89. writer.newLine();
    90. } catch (IOException e) {
    91. e.printStackTrace();
    92. }
    93. }
    94.  
    95. }
    96.  


    As you can see, I only initialize the BufferedWriter after checking that the file does not exist. You should do something similar! Keep me updated how everything works out! ;)
     
  5. Offline

    Gonmarte

    Its not working.
    Code:
    package me.gonmarte;
    
    import java.io.*;
    
    import org.bukkit.command.Command;
    import org.bukkit.command.CommandSender;
    import org.bukkit.configuration.InvalidConfigurationException;
    import org.bukkit.configuration.file.YamlConfiguration;
    import org.bukkit.entity.Player;
    import org.bukkit.plugin.java.JavaPlugin;
    
    public class Main extends JavaPlugin{
       
          private File ClansData;
          private YamlConfiguration cd;
           
           
           
           //Saving my File
          public void saveFiles() {
                try {
                  this.cd.save(this.ClansData);
                } catch (IOException e) {
                  e.printStackTrace();
                 
                }
              }
         
              //Loading my file
              public void loadFiles() {
                if (this.ClansData.exists()){
                  try {
                     
                    this.cd.load(this.ClansData);
                   
                  }catch(IOException e){
                      e.printStackTrace();
                   
                  } catch (InvalidConfigurationException e) {
                    e.printStackTrace();
                   
                }
                  }
              }
             
        @Override
        public void onEnable() {
                ClansData = new File("plugins/" + File.separator + "Clans", "ClansData.yml");
                cd = YamlConfiguration.loadConfiguration(ClansData);
            loadFiles();
           
        }
       
        @Override
        public void onDisable() {
            saveFiles();
        }
       
       
        @Override
        public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
            if(command.getName().equalsIgnoreCase("dog") && sender instanceof Player){
                Dog myDog = new Dog("Billy" , 15);
                if(!ClansData.exists()){
                try {
                    ClansData.createNewFile();
                    ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(ClansData));
                    os.writeObject(myDog);
                    os.close();
                } catch (FileNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
               
                Player p = (Player) sender;
                p.sendMessage("Criaste o teu cao");
                return true;
                }else{
                    try{
                    ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(ClansData));
                    os.writeObject(myDog);
                    os.close();
                } catch (FileNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
               
                Player p = (Player) sender;
                p.sendMessage("Criaste o teu cao");
                return true;
                }
           
        }else if(command.getName().equalsIgnoreCase("mydog") && sender instanceof Player){
            Player p = (Player) sender;
                try {
                    ObjectInputStream in = new ObjectInputStream(new FileInputStream(ClansData));
                    Dog dog = (Dog) in.readObject();
                    in.close();
                    p.sendMessage("O teu cao é: " +dog.name + " e a sua idade: " + dog.age);
                } catch (FileNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (ClassNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
           
            }
            return false;
    }
     
  6. what do you mean it is not working?
     
  7. Offline

    Gonmarte

    It keeps deleting all the data in the reload.
     
  8. @Gonmarte which code did you use? My code or did you adapt your code to my code? If you want to try my code you will have to call new Settings() in your onEnable method
     
  9. Offline

    Gonmarte

    Code:
    package me.gonmarte;
    
    import java.io.*;
    
    import org.bukkit.command.Command;
    import org.bukkit.command.CommandSender;
    import org.bukkit.configuration.InvalidConfigurationException;
    import org.bukkit.configuration.file.YamlConfiguration;
    import org.bukkit.entity.Player;
    import org.bukkit.plugin.java.JavaPlugin;
    
    public class Main extends JavaPlugin{
    
          private File ClansData;
          private YamlConfiguration cd;
      
      
      
           //Saving my File
          public void saveFiles() {
                try {
                  this.cd.save(this.ClansData);
                } catch (IOException e) {
                  e.printStackTrace();
            
                }
              }
    
              //Loading my file
              public void loadFiles() {
                if (this.ClansData.exists()){
                  try {
                
                    this.cd.load(this.ClansData);
              
                  }catch(IOException e){
                      e.printStackTrace();
              
                  } catch (InvalidConfigurationException e) {
                    e.printStackTrace();
              
                }
                  }
              }
        
        @Override
        public void onEnable() {
                ClansData = new File("plugins/" + File.separator + "Clans", "ClansData.yml");
                cd = YamlConfiguration.loadConfiguration(ClansData);
            loadFiles();
      
        }
    
        @Override
        public void onDisable() {
            saveFiles();
        }
    
    
        @Override
        public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
            if(command.getName().equalsIgnoreCase("dog") && sender instanceof Player){
                Dog myDog = new Dog("Billy" , 15);
                if(!ClansData.exists()){
                try {
                    ClansData.createNewFile();
                    ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(ClansData));
                    os.writeObject(myDog);
                    os.close();
                } catch (FileNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
          
                Player p = (Player) sender;
                p.sendMessage("Criaste o teu cao");
                return true;
                }else{
                    try{
                    ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(ClansData));
                    os.writeObject(myDog);
                    os.close();
                } catch (FileNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
          
                Player p = (Player) sender;
                p.sendMessage("Criaste o teu cao");
                return true;
                }
      
        }else if(command.getName().equalsIgnoreCase("mydog") && sender instanceof Player){
            Player p = (Player) sender;
                try {
                    ObjectInputStream in = new ObjectInputStream(new FileInputStream(ClansData));
                    Dog dog = (Dog) in.readObject();
                    in.close();
                    p.sendMessage("O teu cao é: " +dog.name + " e a sua idade: " + dog.age);
                } catch (FileNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (ClassNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
      
            }
            return false;
    }
    }
    
    I used my code. You can see it up. Im can try to use your code, but i dont think it will do any difference.


    EDIT: Maybe its because im creating a new file everytime the plugin is enabled.
     
    Last edited: Apr 10, 2016
  10. @Gonmarte If you think I am sending you my code, it is for you to try my code, not to run your code 200 times and saying it doesn't work without making changes!!!!

    Yes, try not to recreate the file every time, make a check with !file.exists()
     
  11. Offline

    Gonmarte

    I did, Its send me an error. because the file its null cuz its not inisialize.
    I will put my code again.
    You are not saving and loading the file in your code.
    The rest is the same as mine.
    Code:
    package me.gonmarte;
    
    import java.io.*;
    
    import org.bukkit.command.Command;
    import org.bukkit.command.CommandSender;
    import org.bukkit.configuration.InvalidConfigurationException;
    import org.bukkit.configuration.file.YamlConfiguration;
    import org.bukkit.entity.Player;
    import org.bukkit.plugin.java.JavaPlugin;
    
    public class Main extends JavaPlugin{
          
          private File ClansData = new File("plugins/" + File.separator + "Clans", "ClansData.yml");
          private YamlConfiguration cd = YamlConfiguration.loadConfiguration(ClansData);
          
           //Saving my File
          public void saveFiles() {
                try {
                  this.cd.save(this.ClansData);
                } catch (IOException e) {
                  e.printStackTrace();
                
                }
              }
        
              //Loading my file
              public void loadFiles() {
                if (this.ClansData.exists()){
                  try {
                    
                    this.cd.load(this.ClansData);
                  
                  }catch(IOException e){
                      e.printStackTrace();
                  
                  } catch (InvalidConfigurationException e) {
                    e.printStackTrace();
                  
                }
                  }
              }
            
        @Override
        public void onEnable() {
            loadFiles();
          
        }
      
        @Override
        public void onDisable() {
            saveFiles();
        }
      
      
        @Override
        public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
            if(command.getName().equalsIgnoreCase("dog") && sender instanceof Player){
                Dog myDog = new Dog("Billy" , 15);
                if(!ClansData.exists()){
                try {
                    ClansData.createNewFile();
                    FileOutputStream fileOut = new FileOutputStream(ClansData);
                    ObjectOutputStream os = new ObjectOutputStream(fileOut);
                    os.writeObject(myDog);
                    os.close();
                    fileOut.close();
                } catch (FileNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
              
                Player p = (Player) sender;
                p.sendMessage("Criaste o teu cao");
                return true;
                }else{
                    try{
                        FileOutputStream fileOut = new FileOutputStream(ClansData);
                    ObjectOutputStream os = new ObjectOutputStream(fileOut);
                    os.writeObject(myDog);
                    os.close();
                    fileOut.close();
                } catch (FileNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
              
                Player p = (Player) sender;
                p.sendMessage("Criaste o teu cao");
                return true;
                }
          
        }else if(command.getName().equalsIgnoreCase("mydog") && sender instanceof Player){
            Player p = (Player) sender;
                try {
                    FileInputStream fileOut = new FileInputStream(ClansData);
                    ObjectInputStream in = new ObjectInputStream(fileOut);
                    Dog dog = (Dog) in.readObject();
                    in.close();
                    fileOut.close();
                    p.sendMessage("O teu cao é: " +dog.name + " e a sua idade: " + dog.age);
                } catch (FileNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (ClassNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
          
            }
            return false;
    }
    }
     
  12. Offline

    mcdorli

    You never actually create the file
     
  13. Offline

    Gonmarte

    I forgot to add it to loadFiles.
    It still dont work. I added a else statement to the loadFiles, if the file doesnt exist.
    Code:
    package me.gonmarte;
    
    import java.io.*;
    
    import org.bukkit.command.Command;
    import org.bukkit.command.CommandSender;
    import org.bukkit.configuration.InvalidConfigurationException;
    import org.bukkit.configuration.file.YamlConfiguration;
    import org.bukkit.entity.Player;
    import org.bukkit.plugin.java.JavaPlugin;
    
    public class Main extends JavaPlugin{
           
          private File ClansData = new File("plugins/" + File.separator + "Clans", "ClansData.yml");
          private YamlConfiguration cd = YamlConfiguration.loadConfiguration(ClansData);
           
           //Saving my File
          public void saveFiles() {
                try {
                  this.cd.save(this.ClansData);
                } catch (IOException e) {
                  e.printStackTrace();
                 
                }
              }
         
              //Loading my file
              public void loadFiles() {
                if (this.ClansData.exists()){
                  try {
                     
                    this.cd.load(this.ClansData);
                   
                  }catch(IOException e){
                      e.printStackTrace();
                   
                  } catch (InvalidConfigurationException e) {
                    e.printStackTrace();
                   
                }
                  }else{
                      try {
                        cd.save(ClansData);
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                  }
              }
             
        @Override
        public void onEnable() {
            loadFiles();
           
        }
       
        @Override
        public void onDisable() {
            saveFiles();
        }
       
       
        @Override
        public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
            if(command.getName().equalsIgnoreCase("dog") && sender instanceof Player){
                Dog myDog = new Dog("Billy" , 15);
                try {
                    ClansData.createNewFile();
                    FileOutputStream fileOut = new FileOutputStream(ClansData);
                    ObjectOutputStream os = new ObjectOutputStream(fileOut);
                    os.writeObject(myDog);
                    os.close();
                    fileOut.close();
                } catch (FileNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
               
                Player p = (Player) sender;
                p.sendMessage("Criaste o teu cao");
                return true;
           
        }else if(command.getName().equalsIgnoreCase("mydog") && sender instanceof Player){
            Player p = (Player) sender;
                try {
                    FileInputStream fileOut = new FileInputStream(ClansData);
                    ObjectInputStream in = new ObjectInputStream(fileOut);
                    Dog dog = (Dog) in.readObject();
                    in.close();
                    fileOut.close();
                    p.sendMessage("O teu cao é: " +dog.name + " e a sua idade: " + dog.age);
                } catch (FileNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (ClassNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
           
            }
            return false;
    }
    }
    
     
  14. Offline

    mcdorli

    At line 43 you try to save to a file wich doesn't exists, because you called loadFiles from the onEnable, and the file never gets created before that.
     
  15. Offline

    Gonmarte

    I created the file using : new File("---------")
    Anyway i found out a interesting thing, if i put anything in that file using cd.set("a" , "a"); it will be persistent through reloads, but when i put the object it wont.
    Maybe a yaml file cant really store objects and make them persistent through reloads.
    What options do i need? Will i need to use anykind of database like MySql if this problem cant be solved?
     
    Last edited: Apr 11, 2016
  16. Offline

    I Al Istannen

    @Gonmarte
    Are there any errors in the console then? The bukkit YAML normally cries for help if it can't read the file correctly. And you are mixing some things. This is using Java Serialization:
    Code:
     ObjectInputStream in = new ObjectInputStream(fileOut);
                    Dog dog = (Dog) in.readObject();
    but this is using the ConfigurationSerializable and ConfigurationSerialization:
    Code:
          private YamlConfiguration cd = YamlConfiguration.loadConfiguration(ClansData);
    For the latter you would use it like this:
    Code:
    public class Foo implements ConfigurationSerializable {
      
        private int coolInt;
      
        # create a construtor with a Map<String, Object> or a !static! deserialize method
        public Foo(Map<String, Object> map) {
            # restore using the saved variables
            this.coolInt = map.get("coolInt");
        }
    
        # implement the forced serialize method
        public Map<String, Object> serialize() {
            # create map "map"
            map.put("coolInt", coolInt);    # save all the needed variables
            return map;
        }
    }
    Then somewhere BEFORE you EVER call the load method for this config, use this line to make the class known to the Serialization System:
    Code:
            ConfigurationSerialization.registerClass(Foo.class);
    
    Alternatively you could totally stick to the Java Serialization, just don't mix them.

    (ClansData should start with a lowercase character, just for conventions sake)

    Correct my if I dumbly skipped something or said something incorrect!
     
    Gonmarte likes this.
  17. Offline

    Gonmarte

    Sadly i cant sticky to java Serialization, cuz as far i know , yaml files doesnt work to make objects persistant to reloads.
    Honestly, I have already tried to read the javadocs, but i didnt understand nothing about seriliazation on bukkit.
    I also dont understand why i need to create a map to store a save and load a object.
    If you could make a tutorial, on resources or here, or point me some website that actually helps understand ConfigurationSerialization i would apreciate. I have already searched every single link and didnt find anything useful.
    Even the ConfigurationAPI Reference.

    Code:
    map.get("coolInt");
    
    How this is gonna return something if you havent put "coolInt" as a key, and you havent put his value also in the map.
    I really would like to sticky to java, once im pretty more confortable there, but in this case i think i cant (at least i dont know how)
     
  18. Offline

    I Al Istannen

    @Gonmarte
    Well, you are able to store data persistent in yml files (although Zombie_Striker might disagree :D), you will just need to use the ConfigurationApi (or implement your own system).

    The Config API is actually quite simple. You probably already know how to set and get things to a YAMLConfiguration (referred to as yml config). However problems arise if you try to save objects the ConfigurationAPI doesn't know. If you have the Foo class I gave as an example above, there is NO way for the api to know what to save and how to store and retrieve it. It must rely on you giving it this kind of information.

    Now for the actual implementation. The yml config saves the things in a Map like structure:
    Code:
    key: value
    key2:
      subkey: value
    key4: value
    ...
    I hope you can see the similarities.
    To tell the ConfigurationAPI, that your class is able to provide the broken down part and can also be reassembled, you implement the ConfigurationSerializable interface. This forces you to implement the serialize() method, returning a Map<String, Object>. Let's take a look at this. As I have mentioned before, yaml uses a Map-Like structure. Every key is a String, the values can be different (int, double, or an "actual" object). If you have a look at the serialize() method again, you will see that it wants Strings as keys. This is exactly the reason. Now lets look at an example:
    You want to save foo to the key "myFoo". To do this you call "YAMLConfiguration#set("myFoo", fooObject);". The config will now call the serialize() method for fooObject and will get a Map. It will save the data like so:

    Code:
    myFoo: # the key
          ==: path.to.Foo.class # the location to look for the class the object is. Later while reading, it needs to construct the class again. This is how it finds out where the class is.
          coolInt: 1    # The coolInt value we saved to the map in the serialize method.
    You can see that it created the key "coolInt", as we used that as the key in the set method. Now it did it's magic and created a String representation of your object. First it saved what class the object is. In this case it is of type "Foo". Then it saves all the information the serialize() method returned. We just returned a map with "coolInt" as only key and it just wrote it down. Now what happens if we add "superCoolString" to the Map created in serialize() and assign it the value "jup, is cool"?

    As you probably guessed the answer is this:
    Code:
    myFoo: # the key
          ==: path.to.Foo.class # the location to look for the class the object is. Later while reading, it needs to construct the class again. This is how it finds out where the class is.
          coolInt: 1    # The coolInt value we saved to the map in the serialize method.
          superCoolString: "jup, is cool"
    Everything stayed the same, as we didn't change the key in the set method and it is also still the same class. "coolInt" still has a value of 1. But there is one more line: "superCoolString: "jup, is cool"". This is the new key and value we added to the map in the serialize() method. It saved it too. Neat. Now to create your own implementation, you save every field/variable you need to reconstruct the object in the map you return in the serialize() method.

    Now for the constructor. Upon reading the file, YAML sees this key and realises it belongs to an object. It then searches the class after the "==:" and (if you registered it with the ConfigurationSerialization.registerClass) finds it. Now it constructs the map from all things below, taking the left side as the key and the right side as the value. For our object it would look like this:
    Deserialization 1.png
    where green are the keys and blue are the corresponding values.

    In java code it could look like this:
    Code:
    Map<String, Object> objectMap = new HashMap<>();
    objectMap.put("coolInt", 1);
    objectMap.put("superCoolString", "jup, is cool");
    Now it has a Map, but still not the Object that was saved. It now remembers the class it found using the "==:" indicator. Probably using some reflection (don't need to know what that is) it looks for a constructor with a Map<String, Object> as parameter and passes it the now generated map ("objectMap"). Now it has the Object that was saved and can return this object when asked via the config.get() method.

    Without the serialize() method it wouldn't be able to save it as text, without the constructor (or deserialize method) it wouldn't be able to reconstruct the Object from the text.

    I hope this helps and feel free to ask more questions.

    I explained some things not 100% correct, and I just guessed parts of the internal details to make it imho more understandable, don't kill me. I think it will be close enough to be useful, but if I made any fundamental errors, correct me.
     
  19. Offline

    Gonmarte

    @I Al Istannen Acually it was a bit confuse, but then i read your first comment again and i understood. I was switching the serialize with the deserialize method. So i need to create a map to serialize my class right?
    Code:java
    1. package me.gonmarte;
    2.  
    3. import java.util.HashMap;
    4. import java.util.Map;
    5.  
    6. import org.bukkit.configuration.serialization.ConfigurationSerializable;
    7.  
    8. public class Dog implements ConfigurationSerializable{
    9.  
    10. Map<String,Object> myMap = new HashMap<>();
    11.  
    12. public int age;
    13. public String name;
    14.  
    15. public Dog(String name, int age){
    16. this.name=name;
    17. this.age = age;
    18. }
    19.  
    20. public Dog(Map<String, Object> map){
    21. this.age = (int) map.get("age");
    22. this.name = (String) map.get("name");
    23. }
    24.  
    25. @Override
    26. public Map<String, Object> serialize() {
    27. myMap.put("age", this.age);
    28. myMap.put("name", this.name);
    29. return myMap;
    30. }
    31. }


    PS: Just notice, where my yaml file does here? 0.0
     
    Last edited: Apr 11, 2016
  20. Offline

    I Al Istannen

    @Gonmarte
    You don't need to declare the map as a field. It shouldn't be called often enough that caching would make a big difference and keeping variables at the closest scope is always nice :)

    But it should work. Does it?
    You don't need the YAML file in there. But you can now use it like this:
    YAMLConfiguration myYaml = YAMLConfiguration.load(myFile);
    Dog dog = new Dog("Struppi", 10);
    myYaml.set("dogKey", dog);

    and then you can just retrieve it with the key "dogKey", no matter if you save it to a file, reload the server or do something else (as long as you save the yml file).
     
    Gonmarte likes this.
  21. Offline

    Gonmarte

    So what map am i going to use?
    Code:java
    1.  
    2. public Dog(Map<String, Object> map){
    3. this.age = (int) map.get("age");
    4. this.name = (String) map.get("name");
    5. }
    6.  
    7. @Override
    8. public Map<String, Object> serialize() {
    9. //HERE
    10. whatMap.put("age", this.age);
    11. whatMaP.put("name", this.name);
    12. return whatMap;
    13. }
     
  22. Offline

    I Al Istannen

    @Gonmarte
    Just create a new one. At least that is what I do. I think it shouldn't make a big difference, but keeping the variables in a small scopes makes the code a bit more readable (imho).
     
  23. Offline

    Gonmarte

    Inside the method?
    Code:
        @Override
        public Map<String, Object> serialize() {
            Map<String, Object> map = new HashMap<>();
            map.put("age", this.age);
            map.put("name", this.name);
            return map;
        }
    @I Al Istannen Also, i would i get it from the config so i can read?
     
    I Al Istannen likes this.
  24. Offline

    I Al Istannen

    @Gonmarte
    Just like I said you can use the normal getter and setter method of FileConfiguration and therefore also YAMLConfiguration. Just like you saved the String "a" a few posts above. Nothing special. You just need to cast it if retrieved via a getter.
     
  25. Offline

    Gonmarte

    What i did, i could do it without that ConfigurationSerializable thing.
    Its printing me.gonmarte@Dog@123d4 or something like.. i didnt understand yet this thing. Its not changing anything!
    I dont need that thing to make this... and "this" is not what i want.
    Code:
            if(command.getName().equalsIgnoreCase("dog") && sender instanceof Player){
                Dog myDog = new Dog("Billy" , 15);
                cd.set("dog", myDog);
                sender.sendMessage(" "+ cd.get("dog"));
                return true;
    }
     
  26. Offline

    I Al Istannen

    @Gonmarte
    That is the default toString() method. Seems like all is working.
     
  27. Offline

    Gonmarte

    Is working? I can save a object like this, without that two methods. It didnt change anything for god sake. This is not saving an object, java doesntwork this way, what i did is convertins the object to a script string and i dot want that.
     
  28. Offline

    I Al Istannen

    @Gonmarte
    Hey. Calm down dude. You couldn't do that before. You could save it, but after a restart it would habe been deleted. Now that should work.

    EDIT: So to explain that in some more detail. First of "that is not how Java works" is a totally irrelevant and wrong statement. This has nothing to do with Java, but with the Config API. It is written in java, but can use entirely different concepts.

    So A config is internally represented as a HashMap<String, Object>. Of course you can save every Object in there, but after a restart/reload of the config, the data needs to be serialized. And that is where you need the things I said. I think I even stated that in one of my miles long posts - trying to explain it to you.
    So please try to be a bit less rude :)
     
    Last edited: Apr 11, 2016
  29. Offline

    Gonmarte

    Im pretty sure something is not well, when i reload i get a huge error and the file looks strange.
    Caused by IllgalArgumentExeception : Specificaed a class that doesnt exist : me.gonmarte.Dog
    File after the reload error
    Code:
    dog:
      ==: me.gonmarte.Dog
      name: Billy
      age: 15
    
     
  30. Offline

    I Al Istannen

    @Gonmarte
     
Thread Status:
Not open for further replies.

Share This Page