Gson Enchanted Book Serialization to JSON / Storing ItemStacks in MySQL

Discussion in 'Plugin Development' started by ndvenckus1, Oct 5, 2014.

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

    ndvenckus1

    I've spent the past few hours desperately searching for the best way to serialize an ItemStack to a String for storage in a MySQL database, and I've been running into a lot of issues.

    Google's Gson library, which converts java objects to JSON, looked promising, except for when I tried to serialize an enchanted book with this code:
    Code:java
    1.  
    2. //...
    3. Type serializeType = new TypeToken<Map<String, Object>>(){}.getType();
    4. Gson gson = new Gson();
    5. gson.toJson(p.getItemInHand().serialize(), serializeType);
    6. //...
    7.  


    It gave me this error:
    Code:
    org.bukkit.command.CommandException: Unhandled exception executing command 'gson' in plugin VoteSuite v1.0
        at org.bukkit.command.PluginCommand.execute(PluginCommand.java:46) ~[craftbukkit.jar:git-Bukkit-1.7.9-R0.1-10-g8688bd4-b3092jnks]
        at org.bukkit.command.SimpleCommandMap.dispatch(SimpleCommandMap.java:180) ~[craftbukkit.jar:git-Bukkit-1.7.9-R0.1-10-g8688bd4-b3092jnks]
        at org.bukkit.craftbukkit.v1_7_R3.CraftServer.dispatchCommand(CraftServer.java:701) ~[craftbukkit.jar:git-Bukkit-1.7.9-R0.1-10-g8688bd4-b3092jnks]
        at net.minecraft.server.v1_7_R3.PlayerConnection.handleCommand(PlayerConnection.java:956) [craftbukkit.jar:git-Bukkit-1.7.9-R0.1-10-g8688bd4-b3092jnks]
        at net.minecraft.server.v1_7_R3.PlayerConnection.a(PlayerConnection.java:817) [craftbukkit.jar:git-Bukkit-1.7.9-R0.1-10-g8688bd4-b3092jnks]
        at net.minecraft.server.v1_7_R3.PacketPlayInChat.a(PacketPlayInChat.java:28) [craftbukkit.jar:git-Bukkit-1.7.9-R0.1-10-g8688bd4-b3092jnks]
        at net.minecraft.server.v1_7_R3.PacketPlayInChat.handle(PacketPlayInChat.java:47) [craftbukkit.jar:git-Bukkit-1.7.9-R0.1-10-g8688bd4-b3092jnks]
        at net.minecraft.server.v1_7_R3.NetworkManager.a(NetworkManager.java:157) [craftbukkit.jar:git-Bukkit-1.7.9-R0.1-10-g8688bd4-b3092jnks]
        at net.minecraft.server.v1_7_R3.ServerConnection.c(SourceFile:134) [craftbukkit.jar:git-Bukkit-1.7.9-R0.1-10-g8688bd4-b3092jnks]
        at net.minecraft.server.v1_7_R3.MinecraftServer.v(MinecraftServer.java:667) [craftbukkit.jar:git-Bukkit-1.7.9-R0.1-10-g8688bd4-b3092jnks]
        at net.minecraft.server.v1_7_R3.DedicatedServer.v(DedicatedServer.java:260) [craftbukkit.jar:git-Bukkit-1.7.9-R0.1-10-g8688bd4-b3092jnks]
        at net.minecraft.server.v1_7_R3.MinecraftServer.u(MinecraftServer.java:558) [craftbukkit.jar:git-Bukkit-1.7.9-R0.1-10-g8688bd4-b3092jnks]
        at net.minecraft.server.v1_7_R3.MinecraftServer.run(MinecraftServer.java:469) [craftbukkit.jar:git-Bukkit-1.7.9-R0.1-10-g8688bd4-b3092jnks]
        at net.minecraft.server.v1_7_R3.ThreadServerApplication.run(SourceFile:628) [craftbukkit.jar:git-Bukkit-1.7.9-R0.1-10-g8688bd4-b3092jnks]
    Caused by: java.lang.IllegalArgumentException: class org.bukkit.craftbukkit.v1_7_R3.inventory.CraftMetaEnchantedBook declares multiple JSON fields named enchantments
        at org.bukkit.craftbukkit.libs.com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:122) ~[craftbukkit.jar:git-Bukkit-1.7.9-R0.1-10-g8688bd4-b3092jnks]
        at org.bukkit.craftbukkit.libs.com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:72) ~[craftbukkit.jar:git-Bukkit-1.7.9-R0.1-10-g8688bd4-b3092jnks]
        at org.bukkit.craftbukkit.libs.com.google.gson.Gson.getAdapter(Gson.java:353) ~[craftbukkit.jar:git-Bukkit-1.7.9-R0.1-10-g8688bd4-b3092jnks]
        at org.bukkit.craftbukkit.libs.com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:55) ~[craftbukkit.jar:git-Bukkit-1.7.9-R0.1-10-g8688bd4-b3092jnks]
        at org.bukkit.craftbukkit.libs.com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.write(MapTypeAdapterFactory.java:209) ~[craftbukkit.jar:git-Bukkit-1.7.9-R0.1-10-g8688bd4-b3092jnks]
        at org.bukkit.craftbukkit.libs.com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.write(MapTypeAdapterFactory.java:146) ~[craftbukkit.jar:git-Bukkit-1.7.9-R0.1-10-g8688bd4-b3092jnks]
        at org.bukkit.craftbukkit.libs.com.google.gson.Gson.toJson(Gson.java:546) ~[craftbukkit.jar:git-Bukkit-1.7.9-R0.1-10-g8688bd4-b3092jnks]
        at org.bukkit.craftbukkit.libs.com.google.gson.Gson.toJson(Gson.java:525) ~[craftbukkit.jar:git-Bukkit-1.7.9-R0.1-10-g8688bd4-b3092jnks]
        at org.bukkit.craftbukkit.libs.com.google.gson.Gson.toJson(Gson.java:480) ~[craftbukkit.jar:git-Bukkit-1.7.9-R0.1-10-g8688bd4-b3092jnks]
        at org.bukkit.craftbukkit.libs.com.google.gson.Gson.toJson(Gson.java:460) ~[craftbukkit.jar:git-Bukkit-1.7.9-R0.1-10-g8688bd4-b3092jnks]
        at com.gmail.innatefulness.votesuite.VoteSuite.onCommand(VoteSuite.java:79) ~[?:?]
        at org.bukkit.command.PluginCommand.execute(PluginCommand.java:44) ~[craftbukkit.jar:git-Bukkit-1.7.9-R0.1-10-g8688bd4-b3092jnks]
        ... 13 more
    
    There are multiple fields named "enchantments" and it fails to serialize. After looking for a solution to the error, I stumbled upon a stackoverflow thread, which provided me with this ExclusionStrategy that searches for the same field name in all of the class's superclasses, and if it exists, skips the field:
    Code:java
    1.  
    2. import java.lang.reflect.Field;
    3.  
    4. import org.bukkit.craftbukkit.libs.com.google.gson.ExclusionStrategy;
    5. import org.bukkit.craftbukkit.libs.com.google.gson.FieldAttributes;
    6.  
    7. public class SuperclassExclusionStrategy implements ExclusionStrategy
    8. {
    9. public boolean shouldSkipClass(Class<?> arg0)
    10. {
    11. return false;
    12. }
    13.  
    14. public boolean shouldSkipField(FieldAttributes fieldAttributes)
    15. {
    16. String fieldName = fieldAttributes.getName();
    17. Class<?> theClass = fieldAttributes.getDeclaringClass();
    18.  
    19. return isFieldInSuperclass(theClass, fieldName);
    20. }
    21.  
    22. private boolean isFieldInSuperclass(Class<?> subclass, String fieldName)
    23. {
    24. Class<?> superclass = subclass.getSuperclass();
    25. Field field;
    26.  
    27. while(superclass != null)
    28. {
    29. field = getField(superclass, fieldName);
    30.  
    31. if(field != null)
    32. return true;
    33.  
    34. superclass = superclass.getSuperclass();
    35. }
    36.  
    37. return false;
    38. }
    39.  
    40. private Field getField(Class<?> theClass, String fieldName)
    41. {
    42. try
    43. {
    44. return theClass.getDeclaredField(fieldName);
    45. }
    46. catch(Exception e)
    47. {
    48. return null;
    49. }
    50. }
    51. }


    But when I use this code, the enchantments fail to serialize at all, and for a protection IV book, I'm left with this:
    Code:
    {"type":"ENCHANTED_BOOK","meta":["repairCost:0]}
    I don't see how this is happening. When I don't use the ExclusionStrategy, there are multiple "enchantments" fields, but when I do use it, even though it when present in the superclass, there are no "enchantments" fields.

    Could anyone give me a solution to this problem, or present me with a better way of storing ItemStacks in a MySQL database?
     
  2. Offline

    rbrick

    Just serialize the book your self its not hard at all.
     
  3. Offline

    ndvenckus1

    Why should I? There's already a perfectly good library available in the Bukkit API; why reinvent the wheel? All I need to do is fix an error with a single type of item.
     
  4. Offline

    ndvenckus1

    Is there no one out there who's found a way to reliably serialize enchanted books to strings?
     
  5. Offline

    CraftCreeper6

  6. Offline

    ndvenckus1

    Enchanted books, not written books. Anyway, since my last post, I've gotten pretty far into my own method of serialization. I'd be happy to share it once I'm finished.
     
Thread Status:
Not open for further replies.

Share This Page