machinery
machinery

Reputation: 6290

Serialization with singleton design pattern

I have a problem with serialization of a class using the singleton pattern. First let me introduce the code:

import java.io.ObjectStreamException;
import java.io.Serializable;

import org.ejml.simple.SimpleMatrix;

public class Operation implements Serializable {

    private static final long serialVersionUID = 1L;

    private final static int CONSTANT = 10;

    private SimpleMatrix data;
    private Long timestamp;

    private static Operation instance = new Operation ();

    private Operation () {
        data = new SimpleMatrix(1, CONSTANT);
    }

    protected static Operation getInstance() {
        return instance;
    }

    //Hook for not breaking the singleton pattern while deserializing.
    private Object readResolve() throws ObjectStreamException {
          return instance;
    }


    protected void setData(SimpleMatrix matrix) {
        this.data = matrix;
    }

    protected SimpleMatrix getData() {
        return data;
    }

    public Long getTimestamp() {
        return timestamp;
    }

    public void setTimestamp(Long timestamp) {
        this.timestamp = timestamp;
    }
}

I have three problems with it hoping that somebody can help me:

  1. As far as I know, static fields are no serialized. So if I deserialize is my final static field CONSTANT set to 10? If not, how can I make this? This is very important.

  2. As you can see, in the constructor a new matrix is created. If I deserialize, is my data overwritten by this constructor? For deserialization I want the data of the serialized version and not a new matrix. The constructor I only need the first time before serialization to instantiate the object.

  3. Before I serialize I will set the field timestamp to the time of serialization. After deserialization I would like to compare this field with the timestamp of some files (to see if files have changed since serialization). What sort of timestamp should I use for both the serialization time and the last modified time of files so that I can easily compare?

Upvotes: 1

Views: 2463

Answers (2)

Xipo
Xipo

Reputation: 1823

I would suggest that you adopt the Enum Singleton approach for implementing Singletons, as handling Serialization would be done for free. In your case it would be

public enum Operation {
    INSTANCE; 
    // No need to handle Serialization 
}

Quoting Joshua Bloch in Effective Java "a single-element enum type is the best way to implement a singleton."

There are plenty benefits to this approach, you can find out here
And also For instance control, prefer enum types to readResolve

Upvotes: 0

JP Moresmau
JP Moresmau

Reputation: 7403

  1. The static constant is associated with the class, so serialization and deserialization of your instance won't impact it at all.

  2. For the deserialization to work, you need to set the singleton's data to the deserialized instance data:

    private Object readResolve() throws ObjectStreamException {
        instance.setData(getData());
        return instance;
    }
    
  3. The timestamp can stay as a Long, that's fine. Use System.currentTimeMillis(), you'll be able to compare with a File object lastModified() date. Just set the field when you serialize:

    private void writeObject(java.io.ObjectOutputStream out)
        throws IOException{
        timestamp=System.currentTimeMillis();
        out.defaultWriteObject();
    }
    

A test I've made to be sure of what I say, using a String instead of a matrix as in your code:

public static void main(String[] args) throws Exception {
    Operation op=getInstance();
    op.setData("test1");
    byte[] ds=serialize();
    System.out.println(new Date(getInstance().timestamp));
    op.setData("test2");
    deserialize(ds);
    System.out.println(getInstance().getData());

}

This gives me the current date and test1, since the deserialize instance has overriden the current instance. serialize and deserialize simply convert between the instance and bytes.

Upvotes: 2

Related Questions