5

This the part where I use the serialisable interface. when I start the program it will create the same object for each list, but with different references. Is there any way to get them all as one reference?

private static void quitApplication(){
    System.out.println("Stopping the system...\n");
    ///store all the objects by serializing
    try {
        FileOutputStream fileOut2 = new FileOutputStream("FlightList.ser");
        ObjectOutputStream out2 = new ObjectOutputStream(fileOut2);
        out2.writeObject(Flight.getFlights());
        out2.close();
        fileOut2.close();
    }catch(IOException i) {
        System.out.println("FlightList.ser ERROR");
    }

    try {
        FileOutputStream fileOut = new FileOutputStream("CityList.ser");
        ObjectOutputStream out = new ObjectOutputStream(fileOut);
        out.writeObject(City.getCityList());
        out.close();
        fileOut.close();
    }catch(IOException i) {
        System.out.println("CityList.ser ERROR");
    }

    try {
        FileOutputStream fileOut1 = new FileOutputStream("GrapghL.ser");
        ObjectOutputStream out1 = new ObjectOutputStream(fileOut1);
        out1.writeObject(Test.flightGraph);
        out1.close();
        fileOut1.close();
    }catch(IOException i) {
        System.out.println("GrapghL.ser ERROR");
    }
    System.out.println("Done...Thank You For using the Airlines System");
    }

private static void initializeData(){
    try {
        FileInputStream fileIn = new FileInputStream("CityList.ser");
        ObjectInputStream in = new ObjectInputStream(fileIn);
        City.setCityList((MyList<City>) in.readObject());   
        in.close();
        fileIn.close();
    }catch(Exception i){
        System.out.println("CityList.ser ERROR");
    }

    try {
        FileInputStream fileIn2 = new FileInputStream("FlightList.ser");
        ObjectInputStream in2 = new ObjectInputStream(fileIn2);
        Flight.setFlights((MyList<Flight>) in2.readObject());   
        in2.close();
        fileIn2.close();

    }catch(Exception i){
        System.out.println("FlightList.ser ERROR");
    }

    try {
        FileInputStream fileIn1 = new FileInputStream("GrapghL.ser");
        ObjectInputStream in1 = new ObjectInputStream(fileIn1);
        Test.flightGraph = (DefaultDirectedWeightedGraph<City, DefaultWeightedEdge>) in1.readObject();  
        in1.close();
        fileIn1.close();

    }catch(Exception i){
        System.out.println("GrapghL.ser ERROR");
    }
}
user207421
  • 305,947
  • 44
  • 307
  • 483
  • 2
    You have to override readObject/writeObject methods. And make a sort of EntityManager in them. http://stackoverflow.com/questions/12963445/serialization-readobject-writeobject-overides – Mikhail Dec 18 '13 at 09:56
  • To clarify, are you wanting singleton values, like [`Currency`](http://docs.oracle.com/javase/7/docs/api/java/util/Currency.html)? – chrylis -cautiouslyoptimistic- Dec 18 '13 at 09:59
  • Mikhail, can the entities be in deferent classes ? – user2785061 Dec 18 '13 at 10:12
  • chrylis, yes, when I create a city it's added to `GraphL` when I rerun the system the `cityList` and `GraphL` have the same objects but with deferent references – user2785061 Dec 18 '13 at 10:14
  • You could implement a custom readResolve() method. @user2785061 The word is 'different', not 'deferent'. – user207421 Dec 19 '13 at 11:54

1 Answers1

0

There actually is an official Java-tutorial on this. As mentioned by EJP you implement readResolve().

I rewrote the example-class for Java 1.6+: ;-)

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

public class RememberMe implements Serializable {

    /**
     * Contains all known instances by id. If you feel the need to permanently discard an object you have to remove it from this Map.
     */
    static final Map<Integer, RememberMe> knownInstances = new HashMap<Integer, RememberMe>();

    /**
     * There is always only one object by this id reachable
     */
    private final int    id;
    /**
     * A changeable field
     */
    private       String name;
    /**
     * Another changeable field
     */
    private       String location;

    /**
     * Private constructor so we can ship existing instances
     */
    private RememberMe(final int id, final String name, final String location) {
        this.id = id;
        this.name = name;
        this.location = location;
    }

    /**
     * This is how you create and access objects of this class. name and location are ignored if an id already exists
     */
    public static RememberMe getRememberMe(int id, String name, String location) {
        synchronized (knownInstances) {
            final RememberMe oldValue = knownInstances.get(id);
            if(oldValue != null) {
                return oldValue;
            } else {
                final RememberMe newValue = new RememberMe(id, name, location);
                knownInstances.put(id, newValue);
                return newValue;
            }
        }
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getLocation() {
        return location;
    }

    public void setLocation(String location) {
        this.location = location;
    }

    /**
     * This function is called after the Object is fully created (i.e. after constructor was called and all objects
     * referenced by field have been created). Now we only need to decide if it is the first of it's kind or we already
     * know an object by that id.
     */
    private Object readReplace() throws ObjectStreamException {
        synchronized (knownInstances) {
            final RememberMe oldValue = knownInstances.get(id);
            if(oldValue != null) {
                return oldValue;
            } else {
                knownInstances.put(id, this);
                return this;
            }
        }
    }
}

How this works?

  • There is a map knowing all instances of the class
  • If an object is deserialized we use readReplace() to replace it by any instance previously created with the same id.

You need to watch out, that during Object-creation the Object does not register itself anywhere as those references would not be changed by readReplace(); because of this the class is registered in knownInstances inside getRememberMe and not inside the constructor!

If you want to be able to let the GC recycle objects of this class you may want to replace HashMap or its values by some Weak*-variant.

TheConstructor
  • 4,285
  • 1
  • 31
  • 52