Neil Derno
Neil Derno

Reputation: 87

Serializing HashMap with a custom serialized object

I declare the HashMap, inside the ActionHandler class:

public class ActionHandler {
    private HashMap<Cooldown, Long> cooldowns = new HashMap<Cooldown, Long>();

    public void disInit(Main main) throws FileNotFoundException, IOException{
        String path = main.getDataFolder() + File.separator + "cooldowns.dat";
        File serialize = new File(path);
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(serialize));
        oos.writeObject(cooldowns);
        oos.flush();
        oos.close();
        serialize.createNewFile();
    }
}

 

public class Cooldown implements Serializable{
    private static final long serialVersionUID = 2233153996259053084L;
    private String username;
    private Shop shop;
    public Cooldown(String username, Shop shop){
        //constructing setting the fields...
    }
    public String getUsername(){//returning the fields
    public Shop getShop(){//return shop;}
}

The console spits out this error whenever the plugin serializes the file (with disInit). I am stoked because I am already implementing Serializable for my cooldowns class.

[21:16:29 WARN]: java.io.NotSerializableException: com.gmail.ketracoder.vts.Main

[21:16:29 WARN]:        at java.io.ObjectOutputStream.writeObject0(ObjectOutputS
tream.java:1184)
[21:16:29 WARN]:        at java.io.ObjectOutputStream.defaultWriteFields(ObjectO
utputStream.java:1548)
[21:16:29 WARN]:        at java.io.ObjectOutputStream.writeSerialData(ObjectOutp
utStream.java:1509)
[21:16:29 WARN]:        at java.io.ObjectOutputStream.writeOrdinaryObject(Object
OutputStream.java:1432)
[21:16:29 WARN]:        at java.io.ObjectOutputStream.writeObject0(ObjectOutputS
tream.java:1178)
[21:16:29 WARN]:        at java.io.ObjectOutputStream.defaultWriteFields(ObjectO
utputStream.java:1548)
[21:16:29 WARN]:        at java.io.ObjectOutputStream.writeSerialData(ObjectOutp
utStream.java:1509)
[21:16:29 WARN]:        at java.io.ObjectOutputStream.writeOrdinaryObject(Object
OutputStream.java:1432)
[21:16:29 WARN]:        at java.io.ObjectOutputStream.writeObject0(ObjectOutputS
tream.java:1178)
[21:16:29 WARN]:        at java.io.ObjectOutputStream.writeObject(ObjectOutputSt
ream.java:348)
[21:16:29 WARN]:        at java.util.HashMap.internalWriteEntries(HashMap.java:1
776)
[21:16:29 WARN]:        at java.util.HashMap.writeObject(HashMap.java:1354)
[21:16:29 WARN]:        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native M
ethod)
[21:16:29 WARN]:        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMet
hodAccessorImpl.java:62)
[21:16:29 WARN]:        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Deleg
atingMethodAccessorImpl.java:43)
[21:16:29 WARN]:        at java.lang.reflect.Method.invoke(Method.java:483)
[21:16:29 WARN]:        at java.io.ObjectStreamClass.invokeWriteObject(ObjectStr
eamClass.java:988)
[21:16:29 WARN]:        at java.io.ObjectOutputStream.writeSerialData(ObjectOutp
utStream.java:1496)
[21:16:29 WARN]:        at java.io.ObjectOutputStream.writeOrdinaryObject(Object
OutputStream.java:1432)
[21:16:29 WARN]:        at java.io.ObjectOutputStream.writeObject0(ObjectOutputS
tream.java:1178)
[21:16:29 WARN]:        at java.io.ObjectOutputStream.writeObject(ObjectOutputSt
ream.java:348)
[21:16:29 WARN]:        at com.gmail.ketracoder.vts.Shop.ActionHandler.disInit(A
ctionHandler.java:39)
[21:16:29 WARN]:        at com.gmail.ketracoder.vts.Main.onDisable(Main.java:165
)
[21:16:29 WARN]:        at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlug
in.java:323)
[21:16:29 WARN]:        at org.bukkit.plugin.java.JavaPluginLoader.disablePlugin
(JavaPluginLoader.java:359)
[21:16:29 WARN]:        at org.bukkit.plugin.SimplePluginManager.disablePlugin(S
implePluginManager.java:424)
[21:16:29 WARN]:        at org.bukkit.plugin.SimplePluginManager.disablePlugins(
SimplePluginManager.java:417)
[21:16:29 WARN]:        at org.bukkit.craftbukkit.v1_8_R1.CraftServer.disablePlu
gins(CraftServer.java:334)
[21:16:29 WARN]:        at net.minecraft.server.v1_8_R1.MinecraftServer.stop(Min
ecraftServer.java:430)
[21:16:29 WARN]:        at net.minecraft.server.v1_8_R1.MinecraftServer.run(Mine
craftServer.java:561)
[21:16:29 WARN]:        at java.lang.Thread.run(Thread.java:745)

The only time I put something in the HashMap, is when I call:

private void setCooldown(Player player, int slot, Main main, Shop shop){
        String playerName = player.getName();
        Cooldown cooldown = new Cooldown(playerName, shop);
        cooldowns.put(cooldown, System.currentTimeMillis());
}

Upvotes: 0

Views: 1968

Answers (2)

Holger
Holger

Reputation: 298143

If you look for a non-java.io related method, starting from the deepest stacktrace entry, you will find java.util.HashMap.writeObject which is responsible for storing the objects contained in the Map. If a non-Serializable object like com.gmail.ketracoder.vts.Main is encountered during this process, it’s clear that you must have put it into the map before your attempt to serialize it, either as a key or a value (well, or both).

If you want to serialize a map, all objects contained in the map must be Serializable. Unlike, e.g. listeners on AWT components, there is no skipping of non-Serializable objects.

But note that what you are doing is dangerous. If an instance of Main is contained in the map while Main will, in turn, have a reference to the map (I guess that from the class name), you have a cyclic reference. While Serialization works in principle with cyclic object graphs, it will be very fragile when these are combined with HashMaps. The HashMap needs to rehash all elements when restoring the map, which may cause hashCode and equals invoked on incomplete objects in the case of cyclic object graphs.

Upvotes: 1

user207421
user207421

Reputation: 310884

The Cooldown class is what is causing the problem

No, the Main class is what is causing the problem, as the exception says:

java.io.NotSerializableException: com.gmail.ketracoder.vts.Main

Clearly Cooldown is an inner class of Main, so it retains a reference to the enclosing object, which isn't serializable. Make it a static class, or an outer class.

NB calling createNewFile() in the place where you call it will yield a zero length file. You don't need to do that anywhere: new FileOutputStream(...) already does that. Just remove it.

Upvotes: 2

Related Questions