Solved Can't find a codec for class org.bukkit.craftbukkit.v1_16_R3.inventory.CraftMetaItem

Discussion in 'Plugin Development' started by Chr0mosom3, Dec 18, 2020.

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

    Chr0mosom3

    I am getting this error when I try to serialize an item stack
    Code:
    Can't find a codec for class org.bukkit.craftbukkit.v1_16_R3.inventory.CraftMetaItem
    I do not get this error when I try to serialize the item in the players hand, I also do not get it when I try to serialize an item in a random Vendor's inventory.

    Full error
    Log (open)

    Code:
    [16:50:36] [Server thread/ERROR]: Error occurred while disabling ApocalypseZ v1.0 (Is it up to date?)
    org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class org.bukkit.craftbukkit.v1_16_R3.inventory.CraftMetaItem.
        at org.bson.internal.CodecCache.getOrThrow(CodecCache.java:57) ~[bson-4.1.1.jar:?]
        at org.bson.internal.ProvidersCodecRegistry.get(ProvidersCodecRegistry.java:64) ~[bson-4.1.1.jar:?]
        at org.bson.internal.ChildCodecRegistry.get(ChildCodecRegistry.java:52) ~[bson-4.1.1.jar:?]
        at org.bson.codecs.MapCodec.writeValue(MapCodec.java:174) ~[bson-4.1.1.jar:?]
        at org.bson.codecs.MapCodec.encode(MapCodec.java:113) ~[bson-4.1.1.jar:?]
        at org.bson.codecs.MapCodec.encode(MapCodec.java:40) ~[bson-4.1.1.jar:?]
        at com.mongodb.client.model.BuildersHelper.encodeValue(BuildersHelper.java:37) ~[mongodb-driver-core-4.1.1.jar:?]
        at com.mongodb.client.model.Updates$SimpleUpdate.toBsonDocument(Updates.java:511) ~[mongodb-driver-core-4.1.1.jar:?]
        at com.mongodb.internal.operation.Operations.toBsonDocument(Operations.java:538) ~[mongodb-driver-core-4.1.1.jar:?]
        at com.mongodb.internal.operation.Operations.bulkWrite(Operations.java:400) ~[mongodb-driver-core-4.1.1.jar:?]
        at com.mongodb.internal.operation.Operations.updateOne(Operations.java:337) ~[mongodb-driver-core-4.1.1.jar:?]
        at com.mongodb.internal.operation.SyncOperations.updateOne(SyncOperations.java:181) ~[mongodb-driver-core-4.1.1.jar:?]
        at com.mongodb.client.internal.MongoCollectionImpl.executeUpdate(MongoCollectionImpl.java:994) ~[mongodb-driver-sync-4.1.1.jar:?]
        at com.mongodb.client.internal.MongoCollectionImpl.updateOne(MongoCollectionImpl.java:578) ~[mongodb-driver-sync-4.1.1.jar:?]
        at com.mongodb.client.internal.MongoCollectionImpl.updateOne(MongoCollectionImpl.java:573) ~[mongodb-driver-sync-4.1.1.jar:?]
        at eu.ladeira.apocalypse.Database.saveVendors(Database.java:300) ~[?:?]
        at eu.ladeira.apocalypse.Vendor.unloadVendors(Vendor.java:102) ~[?:?]
        at eu.ladeira.apocalypse.ApocalypseZ.onDisable(ApocalypseZ.java:117) ~[?:?]
        at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlugin.java:265) ~[spigot-1.16.4.jar:git-Spigot-a19903d-5b74714]
        at org.bukkit.plugin.java.JavaPluginLoader.disablePlugin(JavaPluginLoader.java:376) ~[spigot-1.16.4.jar:git-Spigot-a19903d-5b74714]
        at org.bukkit.plugin.SimplePluginManager.disablePlugin(SimplePluginManager.java:501) ~[spigot-1.16.4.jar:git-Spigot-a19903d-5b74714]
        at org.bukkit.plugin.SimplePluginManager.disablePlugins(SimplePluginManager.java:493) ~[spigot-1.16.4.jar:git-Spigot-a19903d-5b74714]
        at org.bukkit.craftbukkit.v1_16_R3.CraftServer.disablePlugins(CraftServer.java:428) ~[spigot-1.16.4.jar:git-Spigot-a19903d-5b74714]
        at net.minecraft.server.v1_16_R3.MinecraftServer.stop(MinecraftServer.java:716) ~[spigot-1.16.4.jar:git-Spigot-a19903d-5b74714]
        at net.minecraft.server.v1_16_R3.DedicatedServer.stop(DedicatedServer.java:650) ~[spigot-1.16.4.jar:git-Spigot-a19903d-5b74714]
        at net.minecraft.server.v1_16_R3.MinecraftServer.w(MinecraftServer.java:888) ~[spigot-1.16.4.jar:git-Spigot-a19903d-5b74714]
        at net.minecraft.server.v1_16_R3.MinecraftServer.lambda$0(MinecraftServer.java:164) ~[spigot-1.16.4.jar:git-Spigot-a19903d-5b74714]
        at java.lang.Thread.run(Unknown Source) [?:1.8.0_271]
    


    The relevant methods from my classes:
    Database (open)

    Code:
    public static void saveVendors(Server serverType, ArrayList<Vendor> vendors) {
            for (Vendor vendor : vendors) {
                ItemStack[] items = vendor.getInventory().getContents();
                for (int i = 0; i < items.length; i++) {
                    if (items[i] != null) {
                        servers.updateOne(eq("server", serverType.toString()), set("vendors." + vendor.getName() + "." + i, items[i].serialize()));
                    } else {
                        servers.updateOne(eq("server", serverType.toString()), set("vendors." + vendor.getName() + "." + i, "empty"));
                    }
                }
            }
        }
    

    (The Vendor.unloadVendors() just gets a list of vendors and calls the saveVendors() method, I know that is not the problem)
    (Vendor is a custom player that extends the EntityPlayer class)

    SOLVED

    The issue was not with bukkit itself but was with the way I saved the ItemStack to the MongoDB Java Driver. I had to use POJOs (Plain Old Java Objects) to save the serialized itemstack.

    How I fixed it:
    MongoDB information (open)

    When constructing your MongoClientSettings add this piece of code:
    Code:
    CodecRegistry pojoCodecRegistry = fromRegistries(MongoClientSettings.getDefaultCodecRegistry(), fromProviders(PojoCodecProvider.builder().automatic(true).build()));
    and in your MongoClientSettings builder add
    Code:
    .codecRegistry(pojoCodecRegistry)
    so the final version of the MongoClientSettings builder would look something like this (yours will look different)
    Code:
    MongoClientSettings settings = MongoClientSettings.builder()
                    .credential(MongoCredential.createScramSha256Credential(username, auth_database, password.toCharArray()))
                    .applyToClusterSettings(builder -> 
                        builder.hosts(Arrays.asList(new ServerAddress(hostname, port))))
                    .codecRegistry(pojoCodecRegistry)
                    .build();
    
    Essentially what this does, is implement a codec registry, that: "The codec registry will automatically try to create a POJO Codec for unknown classes" see more: MongoDB Java Driver Documentation

    The reason you need this, is when you serialize the ItemStack, it saves it as a HashMap<String, Object> and by default MongoDB does not know what to do with Object, but when you implement the codec, it tells MongoDB to just make a Plain Old Java Object (hence POJO).


    More about POJOs
    Thread on StackOverflow about POJOs

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Dec 18, 2020
Thread Status:
Not open for further replies.

Share This Page