Search code examples
javaserializable

Serializable by extending with empty constructor?


TLDR: Is there a way to force to a subclass to have an empty constructor when the super does not?

I need to be to initialize a non-serializable class, TravelTimeDataArray, from a serialized data container. The TravelTimeDataArray cannot be serialized because it does not implement the Serializable interface, lacks an empty constructor, and uses a non-serializable field of type Link.

public class TravelTimeDataArray implements TravelTimeData {
    private final double[] timeSum;
    private final int[] timeCnt;
    private final double[] travelTimes;
    private final Link link; //I'm not serializable

    public TravelTimeDataArray(final Link link, final int numSlots) {
        this.timeSum = new double[numSlots];
        this.timeCnt = new int[numSlots];
        this.travelTimes = new double[numSlots];
        this.link = link;
        resetTravelTimes();
    }

//getters and setters
}

My first thought was to extend this as a serializable class. Instead of using a Link, I can use a serializable String of it's ID attribute and add the empty constructor.

public class SerialTravelTimeDataArray extends TravelTimeDataArray implements java.io.Serializable{
    private final String linkId = null;  // I am serializable
    public SerialTravelTimeDataArray(){ } 

    public SerialTravelTimeDataArray(TravelTimeDataArray  ttDA){
      // intialize me using ttDA's data
    } 

   // Methods to serialize the fields.

   // Methods to populate super's fields from the deserialized data containers
   }

Since the super does not have an empty constructor, I get an error with the subclass's empty constructor. Is there a way to force to a subclass to have an empty constructor when the super does not?


Solution

  • According to The Serializable Interface:

    A Serializable class must do the following:

    • Implement the java.io.Serializable interface
    • Identify the fields that should be serializable (Use the serialPersistentFields member to explicitly declare them serializable or use the transient keyword to denote nonserializable fields.)
    • Have access to the no-arg constructor of its first nonserializable superclass

    A no-arg constructor of a object's first nonserializable superclass is need to have access because it will be called while deserializing the object. Otherwise, an exception will be thrown. Note that serializing a object do not call its superclass's default constructor and no exception will be thrown.

    If extending a class is not a must, you can consider using encapsulation like follows:

    public class Foo implements Serializable {
    
        private final double[] timeSum;
        private final int[] timeCnt;
        private final double[] travelTimes;
        private final String linkId;
        private final transient TravelTimeDataArray ttDA;
    
    
        public Foo(TravelTimeDataArray ttDA) {
            this.ttDA = ttDA;
            this.timeSum = ttDA.getTimeSum();
            this.timeCnt = ttDA.getTimeCnt();
            this.travelTimes = ttDA.getTravelTimes();
            this.linkId = ttDA.getLink().getId();
        }
    
        // Methods
    }
    

    If you do not need to access TravelTimeDataArray in your class, you can skip the field transient TravelTimeDataArray ttDA. Hope this can help.