Jacinto Resende
Jacinto Resende

Reputation: 443

How to save static variable when I serialize

My Goal: I need to keep the App state exactly in same sate after shutdown, lets say it's equivalent to "suspend" state.

My Problem : I do know that serialization mechanism doesn't save transient variables neither static variables. However I need to maintain the static variables in exactly same state after App suspension/shut down.

Approach-1 : I could save the state of static variable(s) into a different file, using my "file format", and serialize the objects into a different one.

a) Is this the "normal" approach?

Approach-2 : If I extend the ObjectInputStream/ObjectOutputStreamand override the methods readStreamHeader/writeStreamHeaderI can write whatever I want. So I can also write my static variables.

b) Am I doing something I should not?

Here's the code I've written testing approach-2, and seams to work fine. Please note, I'm not a Java programmer, so for it's very important to understand best practices, if there's any in this particular case.

@SuppressWarnings("serial")
class SequenceIdentifier implements Serializable
{
    protected static long seqIdentifier_ = 1L;  //This variable MUST NOT be reseted.
    private long id_; //Object variable to be serialised.

    private SequenceIdentifier(long id)     
    {   id_ = id;
    }
    @Override
    public String toString()
    {   return ("Id : " + id_ + " of " + seqIdentifier_);
    }
    public static SequenceIdentifier newInstance()
    {   return new SequenceIdentifier(seqIdentifier_++);
    }   
}

final class OOStream extends ObjectOutputStream 
{
    public OOStream(OutputStream out) throws IOException
    {   super(out);
    }   
    @Override
    protected void writeStreamHeader() throws IOException
    {   super.writeLong(SequenceIdentifier.seqIdentifier_);
    }
}

final class OIStream extends ObjectInputStream 
{
    public OIStream(InputStream in) throws IOException
    {   super(in);
    }
    @Override
    protected void readStreamHeader() throws IOException 
    {   SequenceIdentifier.seqIdentifier_ = super.readLong();
    }
}

public class Main
{
    public static void dump(ArrayList<SequenceIdentifier> ids)
    {
        for (SequenceIdentifier id : ids)
            System.out.println(id);
    }

    public static void saveData()
    {
        ArrayList<SequenceIdentifier> ids = new ArrayList<>(Arrays.asList(SequenceIdentifier.newInstance(),
                                                                                            SequenceIdentifier.newInstance(),
                                                                                            SequenceIdentifier.newInstance(),
                                                                                            SequenceIdentifier.newInstance()));
        try (OOStream oOut = new OOStream(new FileOutputStream("foo.bin")))
        {   oOut.writeObject(ids);
        } catch (Exception e)
        {   System.err.println(e);
        }       
        dump(ids);
    }

    @SuppressWarnings("unchecked")
    public static void loadData()
    {
        ArrayList<SequenceIdentifier> ids = null;
        try (OIStream oIn = new OIStream(new FileInputStream("foo.bin")))
        {   ids = (ArrayList<SequenceIdentifier>)oIn.readObject(); 
        } catch (Exception e)
        {   System.err.println(e);
        }       
        dump(ids);
    }

    public static void main(String[] args)
    {
        saveData();
        System.out.println("Counter at this point " + SequenceIdentifier.seqIdentifier_);

        SequenceIdentifier.seqIdentifier_ = 0;
        loadData();
        System.out.println("Counter at this point " + SequenceIdentifier.seqIdentifier_);
    }
}

Upvotes: 1

Views: 2378

Answers (2)

user207421
user207421

Reputation: 310860

Several possibilities.

  1. Make it non-static.
  2. Write complementary readObect()/writeObject() methods that call defaultReadObject() and defaultWriteObject() respectively and then serialize/deserialize the field.
  3. Write complementary writeReplace()/readResolve() methods that substitute a proxy object that does contain this member as a non-transient non-static member.
  4. Make the object Externalizable and take complete control of the serialization process yourself in the associated methods.
  5. Review your requirement.

Upvotes: 0

daniu
daniu

Reputation: 14999

I would create a separate Memento-class containing all the relevant data as fields and de-/serialize that.

class MyClassWithStaticFields1 {
    private static String field;
}
class MyClassWithStaticFields2 {
    private static String field;
}

class StaticMemento {
    String field1;
    String field2;
}

// serialization
StaticMemento mem = new StaticMemento();
mem.field1 = MyClassWithStaticFields1.field;
mem.field2 = MyClassWithStaticFields2.field;
outputStream.writeObject(mem);

// deserialize
StaticMemento mem = outputStream.readObject();
MyClassWithStaticFields1.setField(mem.field1);
MyClassWithStaticFields2.setField(mem.field2);

So basically your Approach-1.

Upvotes: 2

Related Questions