Getting object from YML file causing a tag error

Discussion in 'Spigot Plugin Development' started by DecisionsYT, Aug 10, 2018.

  1. In my code, I save to my smelters.yml file using this:

    Code (Text):
     SmelterObject smelterObject = new SmelterObject();
                smelterObject.setLocation(placedBlock.getLocation());
                smelterObject.setDurabilityLevel(1);
                smelterObject.setEfficiencyLevel(1);
                smelterObject.setFortuneLevel(1);
                smelterObject.setLocked(false);
                smelterObject.setOwnerUUID(player.getUniqueId().toString());

                ArrayList<SmelterObject> retrievedSmeltersArrayList;
                configManager.setup();

                if (configManager.getSmeltersFile().get("smelters") != null) {
                    // There are already smelters registered
                    retrievedSmeltersArrayList = (ArrayList<SmelterObject>) plugin.getConfig().get("smelters");
                    retrievedSmeltersArrayList.add(smelterObject);
                    configManager.getSmeltersFile().set("smelters", retrievedSmeltersArrayList);
                    configManager.saveSmeltersFile();
                } else {
                    // Add the first SmelterObject
                    retrievedSmeltersArrayList = new ArrayList<>(Arrays.asList(smelterObject));
                    configManager.getSmeltersFile().set("smelters", retrievedSmeltersArrayList);
                    configManager.saveSmeltersFile();
                }
    As you can see, I create my custom object and add it to my smelters.yml file

    Then, my smelters.yml file appears like this:
    Code (Text):
    smelters:
    - !!com.idleappsinc.furnacespro.SmelterObject
      durabilityLevel: 1
      efficiencyLevel: 1
      fortuneLevel: 1
      location:
        ==: org.bukkit.Location
        world: world
        x: -255.0
        y: 69.0
        z: 354.0
        pitch: 0.0
        yaw: 0.0
      locked: false
      ownerUUID: 1443b61a-6898-452d-acf2-8b50d802c1c8
     
    It adds it to the file and all looks okay.

    However, when I want to retrieve that list, it causes this error in the console:
    Code (Text):
    [11:58:55 ERROR]: Cannot load plugins\FurnacesPro\smelters.yml
    org.bukkit.configuration.InvalidConfigurationException: could not determine a constructor for the tag tag:yaml.org,2002:com.idleappsinc.furnacespro.SmelterObject
    in 'string', line 2, column 3:
        - !!com.idleappsinc.furnacespro.Sm ...
          ^

            at org.bukkit.configuration.file.YamlConfiguration.loadFromString(YamlConfiguration.java:55) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.bukkit.configuration.file.FileConfiguration.load(FileConfiguration.java:162) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.bukkit.configuration.file.FileConfiguration.load(FileConfiguration.java:130) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.bukkit.configuration.file.YamlConfiguration.loadConfiguration(YamlConfiguration.java:178) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at com.idleappsinc.furnacespro.ConfigManager.getSmeltersFile(ConfigManager.java:46) ~[?:?]
            at com.idleappsinc.furnacespro.listeners.PlaceSmelterListener.onPlaceSmelter(PlaceSmelterListener.java:60) ~[?:?]
            at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
            at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[?:?]
            at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[?:?]
            at java.lang.reflect.Method.invoke(Unknown Source) ~[?:?]
            at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.java:304) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:62) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.bukkit.plugin.SimplePluginManager.fireEvent(SimplePluginManager.java:500) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:485) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.bukkit.craftbukkit.v1_13_R1.event.CraftEventFactory.callBlockPlaceEvent(CraftEventFactory.java:153) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at net.minecraft.server.v1_13_R1.ItemStack.placeItem(ItemStack.java:204) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at net.minecraft.server.v1_13_R1.PlayerInteractManager.a(PlayerInteractManager.java:500) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at net.minecraft.server.v1_13_R1.PlayerConnection.a(PlayerConnection.java:1227) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at net.minecraft.server.v1_13_R1.PacketPlayInUseItem.a(PacketPlayInUseItem.java:37) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at net.minecraft.server.v1_13_R1.PacketPlayInUseItem.a(PacketPlayInUseItem.java:1) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at net.minecraft.server.v1_13_R1.PlayerConnectionUtils.a(SourceFile:10) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source) [?:?]
            at java.util.concurrent.FutureTask.run(Unknown Source) [?:?]
            at net.minecraft.server.v1_13_R1.SystemUtils.a(SourceFile:198) [spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at net.minecraft.server.v1_13_R1.MinecraftServer.w(MinecraftServer.java:884) [spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at net.minecraft.server.v1_13_R1.DedicatedServer.w(DedicatedServer.java:411) [spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at net.minecraft.server.v1_13_R1.MinecraftServer.v(MinecraftServer.java:819) [spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at net.minecraft.server.v1_13_R1.MinecraftServer.run(MinecraftServer.java:717) [spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at java.lang.Thread.run(Unknown Source) [?:?]
    Caused by: org.yaml.snakeyaml.constructor.ConstructorException: could not determine a constructor for the tag tag:yaml.org,2002:com.idleappsinc.furnacespro.SmelterObject
    in 'string', line 2, column 3:
        - !!com.idleappsinc.furnacespro.Sm ...
          ^

            at org.yaml.snakeyaml.constructor.SafeConstructor$ConstructUndefined.construct(SafeConstructor.java:541) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.yaml.snakeyaml.constructor.BaseConstructor.constructObjectNoCheck(BaseConstructor.java:204) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.yaml.snakeyaml.constructor.BaseConstructor.constructObject(BaseConstructor.java:193) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.yaml.snakeyaml.constructor.BaseConstructor.constructSequenceStep2(BaseConstructor.java:364) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.yaml.snakeyaml.constructor.BaseConstructor.constructSequence(BaseConstructor.java:348) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.yaml.snakeyaml.constructor.SafeConstructor$ConstructYamlSeq.construct(SafeConstructor.java:499) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.yaml.snakeyaml.constructor.BaseConstructor.constructObjectNoCheck(BaseConstructor.java:204) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.yaml.snakeyaml.constructor.BaseConstructor.constructObject(BaseConstructor.java:193) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.yaml.snakeyaml.constructor.BaseConstructor.constructMapping2ndStep(BaseConstructor.java:453) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.yaml.snakeyaml.constructor.SafeConstructor.constructMapping2ndStep(SafeConstructor.java:184) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.yaml.snakeyaml.constructor.BaseConstructor.constructMapping(BaseConstructor.java:434) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.yaml.snakeyaml.constructor.SafeConstructor$ConstructYamlMap.construct(SafeConstructor.java:521) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.bukkit.configuration.file.YamlConstructor$ConstructCustomObject.construct(YamlConstructor.java:26) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.yaml.snakeyaml.constructor.BaseConstructor.constructObjectNoCheck(BaseConstructor.java:204) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.yaml.snakeyaml.constructor.BaseConstructor.constructObject(BaseConstructor.java:193) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.yaml.snakeyaml.constructor.BaseConstructor.constructDocument(BaseConstructor.java:159) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.yaml.snakeyaml.constructor.BaseConstructor.getSingleData(BaseConstructor.java:146) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.yaml.snakeyaml.Yaml.loadFromReader(Yaml.java:524) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.yaml.snakeyaml.Yaml.load(Yaml.java:437) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.bukkit.configuration.file.YamlConfiguration.loadFromString(YamlConfiguration.java:53) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            ... 28 more
    [11:58:55 ERROR]: Cannot load plugins\FurnacesPro\smelters.yml
    org.bukkit.configuration.InvalidConfigurationException: could not determine a constructor for the tag tag:yaml.org,2002:com.idleappsinc.furnacespro.SmelterObject
    in 'string', line 2, column 3:
        - !!com.idleappsinc.furnacespro.Sm ...
          ^

            at org.bukkit.configuration.file.YamlConfiguration.loadFromString(YamlConfiguration.java:55) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.bukkit.configuration.file.FileConfiguration.load(FileConfiguration.java:162) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.bukkit.configuration.file.FileConfiguration.load(FileConfiguration.java:130) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.bukkit.configuration.file.YamlConfiguration.loadConfiguration(YamlConfiguration.java:178) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at com.idleappsinc.furnacespro.ConfigManager.getSmeltersFile(ConfigManager.java:46) ~[?:?]
            at com.idleappsinc.furnacespro.listeners.PlaceSmelterListener.onPlaceSmelter(PlaceSmelterListener.java:69) ~[?:?]
            at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
            at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[?:?]
            at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[?:?]
            at java.lang.reflect.Method.invoke(Unknown Source) ~[?:?]
            at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.java:304) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:62) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.bukkit.plugin.SimplePluginManager.fireEvent(SimplePluginManager.java:500) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:485) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.bukkit.craftbukkit.v1_13_R1.event.CraftEventFactory.callBlockPlaceEvent(CraftEventFactory.java:153) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at net.minecraft.server.v1_13_R1.ItemStack.placeItem(ItemStack.java:204) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at net.minecraft.server.v1_13_R1.PlayerInteractManager.a(PlayerInteractManager.java:500) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at net.minecraft.server.v1_13_R1.PlayerConnection.a(PlayerConnection.java:1227) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at net.minecraft.server.v1_13_R1.PacketPlayInUseItem.a(PacketPlayInUseItem.java:37) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at net.minecraft.server.v1_13_R1.PacketPlayInUseItem.a(PacketPlayInUseItem.java:1) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at net.minecraft.server.v1_13_R1.PlayerConnectionUtils.a(SourceFile:10) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source) [?:?]
            at java.util.concurrent.FutureTask.run(Unknown Source) [?:?]
            at net.minecraft.server.v1_13_R1.SystemUtils.a(SourceFile:198) [spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at net.minecraft.server.v1_13_R1.MinecraftServer.w(MinecraftServer.java:884) [spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at net.minecraft.server.v1_13_R1.DedicatedServer.w(DedicatedServer.java:411) [spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at net.minecraft.server.v1_13_R1.MinecraftServer.v(MinecraftServer.java:819) [spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at net.minecraft.server.v1_13_R1.MinecraftServer.run(MinecraftServer.java:717) [spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at java.lang.Thread.run(Unknown Source) [?:?]
    Caused by: org.yaml.snakeyaml.constructor.ConstructorException: could not determine a constructor for the tag tag:yaml.org,2002:com.idleappsinc.furnacespro.SmelterObject
    in 'string', line 2, column 3:
        - !!com.idleappsinc.furnacespro.Sm ...
          ^

            at org.yaml.snakeyaml.constructor.SafeConstructor$ConstructUndefined.construct(SafeConstructor.java:541) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.yaml.snakeyaml.constructor.BaseConstructor.constructObjectNoCheck(BaseConstructor.java:204) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.yaml.snakeyaml.constructor.BaseConstructor.constructObject(BaseConstructor.java:193) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.yaml.snakeyaml.constructor.BaseConstructor.constructSequenceStep2(BaseConstructor.java:364) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.yaml.snakeyaml.constructor.BaseConstructor.constructSequence(BaseConstructor.java:348) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.yaml.snakeyaml.constructor.SafeConstructor$ConstructYamlSeq.construct(SafeConstructor.java:499) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.yaml.snakeyaml.constructor.BaseConstructor.constructObjectNoCheck(BaseConstructor.java:204) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.yaml.snakeyaml.constructor.BaseConstructor.constructObject(BaseConstructor.java:193) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.yaml.snakeyaml.constructor.BaseConstructor.constructMapping2ndStep(BaseConstructor.java:453) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.yaml.snakeyaml.constructor.SafeConstructor.constructMapping2ndStep(SafeConstructor.java:184) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.yaml.snakeyaml.constructor.BaseConstructor.constructMapping(BaseConstructor.java:434) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.yaml.snakeyaml.constructor.SafeConstructor$ConstructYamlMap.construct(SafeConstructor.java:521) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.bukkit.configuration.file.YamlConstructor$ConstructCustomObject.construct(YamlConstructor.java:26) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.yaml.snakeyaml.constructor.BaseConstructor.constructObjectNoCheck(BaseConstructor.java:204) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.yaml.snakeyaml.constructor.BaseConstructor.constructObject(BaseConstructor.java:193) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.yaml.snakeyaml.constructor.BaseConstructor.constructDocument(BaseConstructor.java:159) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.yaml.snakeyaml.constructor.BaseConstructor.getSingleData(BaseConstructor.java:146) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.yaml.snakeyaml.Yaml.loadFromReader(Yaml.java:524) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.yaml.snakeyaml.Yaml.load(Yaml.java:437) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            at org.bukkit.configuration.file.YamlConfiguration.loadFromString(YamlConfiguration.java:53) ~[spigot-1.13.jar:git-Spigot-1503de9-200b239]
            ... 28 more
    I believe it shows something is wrong with the "!!" in the smelters.yml file, however it is saving it like that, so I'm not sure as to why it cant read it.

    Any help is appreciated.
     
  2. #2 StarTux, Aug 10, 2018
    Last edited: Aug 10, 2018
  3. Ermm.. I'm new to creating yml files. I've been looking at the links you provided me with and I can't make out how I can check if my object class has been serialized or not. Would you be able to assist me?
     
  4. Seeing the SmelterObject java file would be most helpful; at least the (de)serialization methods. ;)

    But anyway, I can tell from the yml file that you have implemented ConfigurationSerializable and written the serialization method. What Spigot is complaining about is that it doesn't know how to read the object back from a file. The ConfigurationSerializable interface demands that you implement either a static method "valueOf" or "deserialize", or a constructor that takes a Map<String, Object> as sole parameter. In either of these three, you would read your values from the map, such as
    Code (Text):
    public static SmelterObject deserialize(Map<String, Object> map) {
        SmelterObject result = new SmelterObject();
        result.durabilityLevel = ((Number)map.get("durabilityLevel")).intValue();
        ...
        return result;
    }
    Or, we could do it a little bit more elegantly...
    Code (Text):
    public static SmelterObject deserialize(Map<String, Object> map) {
        SmelterObject result = new SmelterObject();
        ConfigurationSection config = new YamlConfiguration().createSection("tmp", map);
        result.durabilityLevel = config.getInt("durabilityLevel");
        ...
        return result;
    }
    So once that is all done, you have to register the class with ConfigurationSerialization, before your config gets loaded. You can do it in the onEnable method of your plugin class, first thing.
    Code (Text):
    @Override public void onEnable() {
        ConfigurationSerialization.registerClass(SmelterObject.class);
        ...
    }
    Once that happens without an error message, you should be good to go. :)
     
    • Like Like x 1
  5. Thanks for your help.

    However I'm having a few issues.

    In my onEnable, it shows this error: http://prntscr.com/kh0zsc

    Also, in the deserialize method, when should I call it and what is the String and Object that I am passing to it?

    My SmelterObject class is:
    Code (Text):
    package com.idleappsinc.furnacespro;

    import org.bukkit.Location;

    public class SmelterObject {

        Location location;
        String ownerUUID;
        int efficiencyLevel, durabilityLevel, fortuneLevel;
        boolean isLocked;

        public Location getLocation() {
            return location;
        }

        public void setLocation(Location location) {
            this.location = location;
        }

        public String getOwnerUUID() {
            return ownerUUID;
        }

        public void setOwnerUUID(String ownerUUID) {
            this.ownerUUID = ownerUUID;
        }

        public int getEfficiencyLevel() {
            return efficiencyLevel;
        }

        public void setEfficiencyLevel(int efficiencyLevel) {
            this.efficiencyLevel = efficiencyLevel;
        }

        public int getDurabilityLevel() {
            return durabilityLevel;
        }

        public void setDurabilityLevel(int durabilityLevel) {
            this.durabilityLevel = durabilityLevel;
        }

        public int getFortuneLevel() {
            return fortuneLevel;
        }

        public void setFortuneLevel(int fortuneLevel) {
            this.fortuneLevel = fortuneLevel;
        }

        public boolean isLocked() {
            return isLocked;
        }

        public void setLocked(boolean locked) {
            isLocked = locked;
        }
    }
     
     
  6. I'm actually a bit surprised that the serialization works without you writing a serialize() method. I guess SnakeYaml can do that. Today I learned.

    Anyway, the way to tell Spigot how to (de)serialize your object to/from a YML file is to have your class implement the ConfigurationSerializable interface and implement the required methods:
    Code (Text):
    public class SmelterObject implements ConfigurationSerializable {
      @Override public Map<String, Object> serialize() { ... }
      public static SmelterObject deserialize(Map<String, Object> map) { ... }
      ...
    }
    And register the class with ConfigurationSerialization, like described above. Once you have done that, you don't have to call any of the (de)serialization methods yourself. You can put your SmelterObject instances in a ConfigurationSection and retrieve it again as a normal object, exactly like you have displayed in your original post. I don't know if you can get around writing the serialization method, seeing that Yaml knows how to do it without your help... perhaps someone more familiar with this part of the framework can jump in and let us know.

    Personally, I find the whole ConfigurationSerialization framework a bit clunky to work with. I have integrated it with a plugin of mine once, and never again, as I find the benefit to be rather minimal. If you want to automate the whole (de)serialization process, check out Gson. It's very popular, but discussing it any further would exceed the scope of this thread. ;-)
     
    #6 StarTux, Aug 10, 2018
    Last edited: Aug 10, 2018
    • Informative Informative x 1
  7. Thanks for your detailed reply.

    I think I might check out Gson then as I've also heard it mentioned and it seems quite popular. Thank you very much for you help though! Much appreciated.