brotheroftux
brotheroftux

Reputation: 87

HashMap saving with ObjectOutputStream

To save teleportation points on command, I have an HashMap:

public HashMap<Player, Location> mapHomes = new HashMap<>();

Which is accessed like this:

if(cmd.getName().equalsIgnoreCase("sethome")){
    Location loc = player.getLocation();
    mapHomes.put(player, loc);
    sender.sendMessage("Home set !");
    return true;
}
if(cmd.getName().equalsIgnoreCase("home")){
    Location loc1 = mapHomes.get(player);
    player.teleport(loc1);
    sender.sendMessage("Teleported to home");
    return true;
}
return false;

Since these settings should be kept on restart, I've implemented a save method:

public void save(HashMap<Player,Location> mapHome, String path) throws NotSerializableException{
    try{
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(path));
        oos.writeObject(mapHome);
        oos.flush();
        oos.close();
    }catch(Exception e){
        e.printStackTrace();
    }
}

But it's not working. It throws NotSerializableException.

I think the main problem is Player and Location are not serializable types, so what should I do to write this HashMap?

Upvotes: 3

Views: 8417

Answers (6)

DeFazer
DeFazer

Reputation: 1

In fact, you are trying to serialize Player and Location, trying to implement new classes etc. But why are you doing this?

It would be better if you store not Player and Location objects, but their String representations instead. For example, you could use Player.getName() and something like "world:100:65:100"for location (so we can easily get all data back by String.split(":"). I think this a better approach.

Upvotes: -2

tibtof
tibtof

Reputation: 7957

HashMap is already Serializable.

The problem is that the objects inside the map are not, so you'll have to make them serializable, too.

public class SerializedPlayer extends Player implements Serializable {
    public SerializedPlayer() {}
    public SerializedPlayer(Player playerToClone) {
        this.setField1(playerToClone.getField1());
        // Set all the fields
    }
}

When adding to the map:

map.put(new SerializedPlayer(player), new SerializedLocation(location));

Upvotes: 2

J.K
J.K

Reputation: 2393

NotSerializableException is thrown when an instance is required to have a Serializable interface.

class YourClass implements Serializable {
    // ...
}

Upvotes: 1

JNorr44
JNorr44

Reputation: 274

To make Location serializable, I recommend using this class. I wrote it myself, and just request you give me credit in the code.

package com.github.JamesNorris.Class;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Server;
import org.bukkit.World;

/**
 * The class that allows location to be serialized, and be used
 * in a file. This class should not be changed, otherwise it
 * will not work for older files.
 * 
 * @author Jnorr44
 */

public final class SerializableLocation implements Serializable {
    private static final long serialVersionUID = 8650311534439769069L;

    private final String world;
    private final String uuid;
    private final double x, y, z;
    private final float yaw, pitch;
    private transient Location loc;

    /**
     * Creates a new SerializableLocation instance of any org.bukkit.Location.
     * 
     * @param l
     */

    public SerializableLocation(Location l) {
        this.world = l.getWorld().getName();
        this.uuid = l.getWorld().getUID().toString();
        this.x = l.getX();
        this.y = l.getY();
        this.z = l.getZ();
        this.yaw = l.getYaw();
        this.pitch = l.getPitch();
    }

    /**
     * Gets the org.bukkit.Location back from any SerializableLocation.
     * 
     * @param l
     * @return
     */

    public static Location returnLocation(SerializableLocation l) {
        float pitch = l.pitch;
        float yaw = l.yaw;
        double x = l.x;
        double y = l.y;
        double z = l.z;
        World world = Bukkit.getWorld(l.world);
        Location location = new Location(world, x, y, z, yaw, pitch);
        return location;
    }

    // FROM HERE ON NEEDS DOC NOTES

    public SerializableLocation(Map<String, Object> map) {
        this.world = (String) map.get("world");
        this.uuid = (String) map.get("uuid");
        this.x = (Double) map.get("x");
        this.y = (Double) map.get("y");
        this.z = (Double) map.get("z");
        this.yaw = ((Float) map.get("yaw")).floatValue();
        this.pitch = ((Float) map.get("pitch")).floatValue();
    }

    public final Map<String, Object> serialize() {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("world", this.world);
        map.put("uuid", this.uuid);
        map.put("x", this.x);
        map.put("y", this.y);
        map.put("z", this.z);
        map.put("yaw", this.yaw);
        map.put("pitch", this.pitch);
        return map;
    }

    public final Location getLocation(Server server) {
        if (loc == null) {
            World world = server.getWorld(this.uuid);
            if (world == null) {
                world = server.getWorld(this.world);
            }
            loc = new Location(world, x, y, z, yaw, pitch);
        }
        return loc;
    }
}

Now simply do:

SerializableLocation loc = new SerializableLocation(LOCATION);

The reason this is required is because Location contains world, x, y, z, yaw and pitch, where world is not serializable.

Upvotes: 0

Nandkumar Tekale
Nandkumar Tekale

Reputation: 16158

I think you are writing HashMap<Player, Location> to file.

What you need to do is make your Player and Location classes serializable.

public class Player implements java.io.Serializable {
    // ...
}

public class Location implements java.io.Serializable {
    // ...
}

HashMap is already serializable.

Upvotes: 0

oopbase
oopbase

Reputation: 11385

class Player implements Serializable {}

class Location implements Serializable {}

Remember, you can only serialize objects that implement the Serializable interface. So your Player and Location class have to implement the interface, too.

Upvotes: 0

Related Questions