When calling ItemStack.deserialize, a casting exception occurs which breaks deserialization.
05.12 22:57:34 [Server] INFO [22:57:34 WARN]: at java.lang.Thread.run(Thread.java:745) 05.12 22:57:34 [Server] INFO [22:57:34 WARN]: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) 05.12 22:57:34 [Server] INFO [22:57:34 WARN]: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) 05.12 22:57:34 [Server] INFO [22:57:34 WARN]: at org.bukkit.craftbukkit.v1_8_R3.scheduler.CraftAsyncTask.run(CraftAsyncTask.java:53) 05.12 22:57:34 [Server] INFO [22:57:34 WARN]: at org.bukkit.craftbukkit.v1_8_R3.scheduler.CraftTask.run(CraftTask.java:71) 05.12 22:57:34 [Server] INFO [22:57:34 WARN]: at com.lumengaming.giftwrap.service.DataService$$Lambda$16/912274127.run(Unknown Source) 05.12 22:57:34 [Server] INFO [22:57:34 WARN]: at com.lumengaming.giftwrap.service.DataService.lambda$getPackageById$6(DataService.java:37) 05.12 22:57:34 [Server] INFO [22:57:34 WARN]: at com.lumengaming.giftwrap.repository.MySqlDataRepository.getPackageById(MySqlDataRepository.java:131) 05.12 22:57:34 [Server] INFO [22:57:34 WARN]: at com.lumengaming.giftwrap.repository.MySqlDataRepository.readPackages(MySqlDataRepository.java:158) 05.12 22:57:34 [Server] INFO [22:57:34 WARN]: at com.lumengaming.giftwrap.SerializerUtility.fromJson(SerializerUtility.java:88) 05.12 22:57:34 [Server] INFO [22:57:34 WARN]: at com.lumengaming.giftwrap.SerializerUtility.deserialize(SerializerUtility.java:139) 05.12 22:57:34 [Server] INFO [22:57:34 WARN]: at org.bukkit.inventory.ItemStack.deserialize(ItemStack.java:533) 05.12 22:57:34 [Server] INFO [22:57:34 WARN]: java.lang.ClassCastException: java.lang.Double cannot be cast to java.lang.Integer 05.12 22:57:12 [22:57:12 INFO]: Pangamma ran command Message of the Day 05.12 22:57:12 [Connect] User [22:57:12 INFO]: Pangamma, IP 127.0.0.1 05.12 22:57:12 [Server] INFO [22:57:12 INFO]: UUID of player Pangamma is f77b713b-7aa0-3854-8208-1b3550c188ca 05.12 22:53:28 [Se
The fix is to make sure the amount is being cast to Number, then the .intValue() method is used to get the int value of the amount.
if (args.containsKey("amount")) { amount = ((Number) args.get("amount")).intValue(); }
[SPIGOT-1325] Deserialization of ItemStack fails.
@md_5
What alternative would you suggest instead of the current solution then? There might be some already-defined method I'm overlooking right now.
I'm using google gson to parse the json into the map types... Then ItemStack.deserialize from there... Warning: Prototype code that looks terrible and will need to be refactored later coming in:
package com.lumengaming.giftwrap; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Base64; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.TreeMap; import java.util.logging.Level; import java.util.logging.Logger; import org.bukkit.Material; import org.bukkit.configuration.serialization.ConfigurationSerialization; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; public class SerializerUtility { //<editor-fold defaultstate="collapsed" desc="Second Attempt"> public static String toJson(final ItemStack[] is){ String json = ""; try{ List<TreeMap<String, Map<String, Object>>> data = serialize(is); Gson gson = new GsonBuilder().serializeNulls().create(); json = gson.toJson(data); // System.out.println(json); // File f = new File("tester.bin"); // FileOutputStream fos; // fos = new FileOutputStream(f); // fos.write(json.getBytes()); } catch (Exception ex){ Logger.getLogger(SerializerUtility.class.getName()).log(Level.SEVERE, null, ex); } return json; } public static String toJsonSingle(final ItemStack is){ String json = ""; try{ List<TreeMap<String, Map<String, Object>>> data = serialize(new ItemStack[]{is}); Gson gson = new GsonBuilder().serializeNulls().create(); json = gson.toJson(data.get(0)); } catch (Exception ex){ Logger.getLogger(SerializerUtility.class.getName()).log(Level.SEVERE, null, ex); } return json; } public static ItemStack fromJsonSingle(final String json){ ItemStack is = null; try{ Gson gson = new GsonBuilder().serializeNulls().create(); // ArrayList<TreeMap<String, Map<String, Object>>> TypeToken tt = new TypeToken<TreeMap<String, Map<String, Object>>>(){}; Type collectionType = tt.getType(); TreeMap<String, Map<String, Object>> fromJson = gson.fromJson(json, collectionType); ArrayList<TreeMap<String, Map<String, Object>>> list = new ArrayList<>(); list.add(fromJson); ItemStack[] deserialize = deserialize(list); return deserialize[0]; } catch (Exception ex){ Logger.getLogger(SerializerUtility.class.getName()).log(Level.SEVERE, null, ex); } return is; } public static ItemStack[] fromJson(final String json){ ItemStack[] is = null; try{ Gson gson = new GsonBuilder().serializeNulls().create(); // ArrayList<TreeMap<String, Map<String, Object>>> TypeToken tt = new TypeToken<ArrayList<TreeMap<String, Map<String, Object>>>>(){}; Type collectionType = tt.getType(); List<TreeMap<String, Map<String, Object>>> fromJson = gson.fromJson(json, collectionType); return deserialize(fromJson); } catch (Exception ex){ Logger.getLogger(SerializerUtility.class.getName()).log(Level.SEVERE, null, ex); } return is; } private static List<TreeMap<String,Map<String,Object>>> serialize(final ItemStack[] itemStackList) { final List<TreeMap<String,Map<String,Object>>> serialized = new ArrayList<>(); for (ItemStack itemStack : itemStackList) { TreeMap<String,Map<String,Object>> sMap = new TreeMap<>(); ItemMeta im = null; try{ if (itemStack == null){ itemStack = new ItemStack(Material.AIR); } im = itemStack.hasItemMeta() ? itemStack.getItemMeta() : null; Map<String, Object> serializedItemMeta = (im != null) ? im.serialize() : null; sMap.put("ItemMeta",serializedItemMeta); }catch(Exception ex){ ex.printStackTrace(); } itemStack.setItemMeta(null); try{ Map<String, Object> serializedItemStack = itemStack.serialize(); sMap.put("ItemStack",serializedItemStack); }catch(Exception ex){ sMap.put("ItemStack", new ItemStack(Material.BARRIER).serialize()); if (sMap.containsKey("ItemMeta")){ sMap.remove("ItemMeta"); } ex.printStackTrace(); } itemStack.setItemMeta(im); serialized.add(sMap); } return serialized; } private static ItemStack[] deserialize(final List<TreeMap<String,Map<String,Object>>> serialized) { final ItemStack[] itemStackList = new ItemStack[serialized.size()]; int i = 0; for (TreeMap<String,Map<String,Object>> sMap : serialized) { try{ Entry<String, Map<String, Object>> serializedItemStack = sMap.entrySet().iterator().next(); if (sMap.containsKey("ItemStack")){ ItemStack is = ItemStack.deserialize(sMap.get("ItemStack")); if (sMap.containsKey("ItemMeta") && sMap.get("ItemMeta") != null){ ItemMeta im = (ItemMeta) ConfigurationSerialization.deserializeObject(sMap.get("ItemMeta"), ConfigurationSerialization.getClassByAlias("ItemMeta")); is.setItemMeta(im); } itemStackList[i++] = is; }else{ itemStackList[i++] = new ItemStack(Material.AIR); } }catch(Exception ex){ ex.printStackTrace(); itemStackList[i++] = new ItemStack(Material.AIR); } } return itemStackList; } //</editor-fold> //<editor-fold defaultstate="collapsed" desc="Base serializers"> private static List<HashMap<Map<String, Object>, Map<String, Object>>> serializeItemStackList(final ItemStack[] itemStackList) { final List<HashMap<Map<String, Object>, Map<String, Object>>> serializedItemStackList = new ArrayList<HashMap<Map<String, Object>, Map<String, Object>>>(); for (ItemStack itemStack : itemStackList) { HashMap<Map<String, Object>, Map<String, Object>> serializedMap = new HashMap<>(); if (itemStack == null) itemStack = new ItemStack(Material.AIR); ItemMeta im = itemStack.hasItemMeta() ? itemStack.getItemMeta() : null; Map<String, Object> serializedItemMeta = (im != null) ? im.serialize() : null; itemStack.setItemMeta(null); Map<String, Object> serializedItemStack = itemStack.serialize(); itemStack.setItemMeta(im); serializedMap.put(serializedItemStack, serializedItemMeta); serializedItemStackList.add(serializedMap); } return serializedItemStackList; } private static ItemStack[] deserializeItemStackList(final List<HashMap<Map<String, Object>, Map<String, Object>>> serializedItemStackList) { final ItemStack[] itemStackList = new ItemStack[serializedItemStackList.size()]; int i = 0; for (HashMap<Map<String, Object>, Map<String, Object>> serializedItemStackMap : serializedItemStackList) { Entry<Map<String, Object>, Map<String, Object>> serializedItemStack = serializedItemStackMap.entrySet().iterator().next(); ItemStack itemStack = ItemStack.deserialize(serializedItemStack.getKey()); if (serializedItemStack.getValue() != null) { ItemMeta itemMeta = (ItemMeta)ConfigurationSerialization.deserializeObject(serializedItemStack.getValue(), ConfigurationSerialization.getClassByAlias("ItemMeta")); itemStack.setItemMeta(itemMeta); } itemStackList[i++] = itemStack; } return itemStackList; } //</editor-fold> //<editor-fold defaultstate="collapsed" desc="Base64"> /** * Returns empty stack on failure. * @param b64Str * @return */ public static ItemStack[] fromBase64Str(final String b64Str){ if (b64Str == null || "".equals(b64Str.trim())) return new ItemStack[0]; return fromBase64(b64Str.getBytes()); } public static ItemStack[] fromBase64(final byte[] b64){ try{ byte[] oBytes = Base64.getDecoder().decode(b64); ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(oBytes)); List<HashMap<Map<String, Object>, Map<String, Object>>> data = (List<HashMap<Map<String, Object>, Map<String, Object>>>) ois.readObject(); return deserializeItemStackList(data); } catch (IOException | ClassNotFoundException ex){ Logger.getLogger(SerializerUtility.class.getName()).log(Level.SEVERE, null, ex); } return new ItemStack[0]; } /** * Returns null on failure. * @param items * @return */ public static String toBase64Str(final ItemStack[] items){ return new String(toBase64(items)); } /** * Returns null on failure. * @param items * @return */ public static byte[] toBase64(final ItemStack[] items){ List<HashMap<Map<String, Object>, Map<String, Object>>> data = serializeItemStackList(items); try{ ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(data); oos.flush(); oos.close(); byte[] oBytes = baos.toByteArray(); return Base64.getEncoder().encode(oBytes); } catch (IOException ex){ Logger.getLogger(SerializerUtility.class.getName()).log(Level.SEVERE, null, ex); } return new byte[0]; } //</editor-fold> //<editor-fold defaultstate="collapsed" desc="Json"> // public static toJson(final ItemStack[] is){ // try{ // List<HashMap<Map<String, Object>, Map<String, Object>>> data = serializeItemStackList(is); // // } // catch (IOException | ClassNotFoundException ex){ // Logger.getLogger(SerializerUtility.class.getName()).log(Level.SEVERE, null, ex); // } // return new ItemStack[0]; // } //</editor-fold> }
JSON? The serializer only supports yaml, via the configuration API.
You are manually calling deserialize and passing an undefined input into the method.
You're right, it does. So I'm not sure why the deserialize method tried to deserialize it as a Double... cast to an Integer. Either way, it's a pretty easy fix. =]
Both Double and Integer extend/implement Number. Number has a method for getting the int value. So just cast to Number, then use the toIntValue() method.
[{"ItemMeta":null,"ItemStack":{"type":"DISPENSER","amount":10}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}},{"ItemMeta":null,"ItemStack":{"type":"AIR"}}]
@md_5 fixed in code? I can't find related commit