Bukkit Version Proof ItemStack Serialization

Discussion in 'Resources' started by Ultimate_n00b, Oct 13, 2013.

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


    1. public class ItemHandler {
    3. public static String toString(ItemStack i) {
    4. return mapToString(i.serialize());
    5. }
    7. public static ItemStack fromString(String s) {
    8. return ItemStack.deserialize(stringToMap(s));
    9. }
    11. private static String mapToString(Map<String, Object> map) {
    12. StringBuilder stringBuilder = new StringBuilder();
    13. for (String key : map.keySet()) {
    14. if (stringBuilder.length() > 0) {
    15. stringBuilder.append("&");
    16. }
    17. String value = map.get(key).toString();
    18. try {
    19. stringBuilder.append((key != null ? URLEncoder.encode(key, "UTF-8") : ""));
    20. stringBuilder.append("=");
    21. stringBuilder.append(value != null ? URLEncoder.encode(value, "UTF-8") : "");
    22. throw new RuntimeException("This method requires UTF-8 encoding support", e);
    23. }
    24. }
    25. return stringBuilder.toString();
    26. }
    28. private static Map<String, Object> stringToMap(String input) {
    29. Map<String, Object> map = new HashMap<String, Object>();
    30. String[] nameValuePairs = input.split("&");
    31. for (String nameValuePair : nameValuePairs) {
    32. String[] nameValue = nameValuePair.split("=");
    33. try {
    34. map.put(URLDecoder.decode(nameValue[0], "UTF-8"),
    35. nameValue.length > 1 ? URLDecoder.decode(nameValue[1], "UTF-8") : "");
    36. throw new RuntimeException("This method requires UTF-8 encoding support", e);
    37. }
    38. }
    40. return map;
    41. }
    42. }

    A quick class a threw together as to serialize itemstacks to strings, then back to itemstacks.
    Chinwe likes this.
  2. Offline


    Ultimate_n00b can this be used with other Objects that implements ConfigurationSerialisation? It would be a nice way so serialize custom object to strings for databases :D
  3. Offline


    MiniDigger I believe so.

    The way I automatically assume the second thing in the map is a String doesn't work in a few cases, so I'm working on a way to fix it.
  4. Offline


    Ultimate_n00b that would be realy nice since i planed to use a database instad of files and I using the serialisation thing for all my custom objects :D.
    Cant i just put a string on second place to avoid this?
  5. Offline


    You might want to look into using JSON, as it is basically designed to do what you're doing, but much cleaner/better.
  6. Offline


    Do I need a lib for json? If so, no thanks.
  7. Offline


    gson is built into bukkit and simple-json is in craftbukkit.

    Also, what's wrong with using the api for this? ConfigurationSerializable and BukkitObjectInputStream work for this :)
  8. Offline


    drtshock I am using the ConfiguartionSerializable but I want it to return a String to put it into a database or something like that. I never heard of BukkitObjectInputStream. Ill google it now :D
    EDIT: I found something but i dont understand it -.-. Are there some ressorces about this to learn it? I found nothing. And I dont what the api docs trying to say me :D
    EDIT 2: Found something, tested it and... got an error https://gist.github.com/MiniDigger/6992945 -.-
  9. Offline


    Take a look at ItemStack's serialize() method:
    1. public Map<String, Object> serialize() {
    2. Map<String, Object> result = new LinkedHashMap<String, Object>();
    4. result.put("type", getType().name());
    6. if (getDurability() != 0) {
    7. result.put("damage", getDurability());
    8. }
    10. if (getAmount() != 1) {
    11. result.put("amount", getAmount());
    12. }
    14. ItemMeta meta = getItemMeta();
    15. if (!Bukkit.getItemFactory().equals(meta, null)) {
    16. result.put("meta", meta);
    17. }
    19. return result;
    20. }

    As you can see, it puts the item's ItemMeta directly into the map without serializing it, so your code will not work for item stacks with enchantments or other data.

    edit: actually it will crash under any circumstances: you load numbers as strings, but ItemStack's deserialize(Map) casts them to Number and Integer, resulting in a ClassCastException. Have you ever tested your code?

    edit 2: to make things more complicated, CraftMetaItem also saves a List<String>. I highly recommend to just use a new YamlConfiguration, save the ItemStack, and use config.saveToString() to get the saved ItemStack:
    1. final YamlConfiguration y = new YamlConfiguration();
    2. y.set("value", is);
    3. return y.saveToString();
  10. Offline


    I have tested my code, being why I have never bumped this thread. I currently use this with it's online counterpart here.
  11. Offline


    Stumbled across this and I thought I'd add a few cents... Isn't this code susceptible to an "item meta injection"?

    For example, if I used an anvil to name an item "a;amount=64" fromString(String) would grab a for the item's name as "a" then set the amount to 64. You could do the same thing to get enchantments, custom lore, etc...

    I mean granted you'd have to know how the name was being stored, but a clever person could really abuse the heck out of this.
    Rayzr522 likes this.
Thread Status:
Not open for further replies.

Share This Page