Main Content

Serialization with Class Hierarchies

When you revise classes in a hierarchy, your hierarchy can inherit from matlab.mixin.CustomElementSerialization and define modifyIncomingSerializationContent and modifyOutgoingSerialization methods to manage the changes.

Call Superclass Methods of matlab.mixin.CustomElementSerialization

In this example, the abstract SensorData superclass is the parent of several subclasses representing different sensors and measurements. In the first version, the superclass defines properties for the data, the first time the data is collected, the interval between data points, and the location of the sensor.

classdef (Abstract) SensorData
    properties
        Data {mustBeVector} = 0
        StartTime = datetime("today",Format="MMMM d, yyyy HH:mm:ss")
        Interval = duration(0,1,0)
        Location {mustBeTextScalar} = ""
    end
end

One of the subclasses, TempData, is designed specifically for temperature data and includes a Units property with validation.

classdef TempData < SensorData
    properties
        Units {mustBeMember(Units,["F","C"])} = "C"
    end
end

Create an instance of TempData.

t1 = TempData;
t1.Data = [15 17 17 16];
t1.Interval = hours(1);
t1.Location = "NW Building 1"
t1 = 

  TempData with properties:

        Units: "C"
         Data: [15 17 17 16]
    StartTime: June 18, 2024 00:00:00
     Interval: 1 hr
     Location: "NW Building 1"

Save t1 and then clear the instance.

save("yourfilepath/SensorTest.mat","t1")
clear t1

In the second version, the SensorData class includes a TimeStamps property. Instead of calculating the time of each data point on demand, this version of the class uses the TimeStamps property to store a vector of times that correspond to each element of the Data property. The class implements modifyIncomingSerializationContent to add the new property during deserialization, if necessary, and calculate the values based on the StartTime and Interval properties.

classdef (Abstract) SensorData < matlab.mixin.CustomElementSerialization
    properties
        Data {mustBeVector} = 0
        TimeStamps {mustBeVector} = datetime("today",Format="MMMM d, yyyy HH:mm:ss")
        StartTime = datetime("today",Format="MMMM d, yyyy HH:mm:ss")
        Interval = duration(0,1,0)
        Location {mustBeTextScalar} = ""
    end
    methods (Static)
        function modifyIncomingSerializationContent(sObj)
            if ~sObj.hasNameValue("TimeStamps")
                ts(1) = sObj.StartTime;
                % Set the last value of ts to the StartTime to
                % preallocate space for the vector.
                ts(length(sObj.Data)) = sObj.StartTime;
                for i = 2:length(sObj.Data)
                    ts(i) = ts(i-1) + sObj.Interval;
                end
                sObj.addNameValue("TimeStamps",ts);
            end
        end
    end
end

To correctly deserialize TempData instances serialized under the older definition of SensorData, the TempData class must implement its own version of modifyIncomingSerializationContent that explicitly calls the superclass modifyIncomingSerializationContent method. MATLAB® does not automatically call matlab.mixin.CustomElementSerialization methods defined by superclasses. The method first checks if the TimeStamps property exists in the data being deserialized. If not, the method calls the superclass modifyIncomingSerializationContent method to create it.

classdef TempData < SensorData
    properties
        Units {mustBeMember(Units,["F","C"])} = "C"
    end
    methods (Static)
        function modifyIncomingSerializationContent(sObj)
            if ~sObj.hasNameValue("TimeStamps")
                modifyIncomingSerializationContent@SensorData(sObj);
            end
        end
    end
end

Load the saved instance t1 under the new definitions of SensorData and TempData. The TimeStamps property is added.

load("yourfilepath/SensorTest.mat","t1")
t1
t1 = 

  TempData with properties:

         Units: "C"
          Data: [15 17 17 16]
    TimeStamps: [June 18, 2024 00:00:00    June 18, 2024 01:00:00    June 18, 2024 02:00:00    June 18, 2024 03:00:00]
     StartTime: June 18, 2024 00:00:00
      Interval: 1 hr
      Location: "NW Building 1"

This example shows how to implement backward compatibility, enabling instances of TempData serialized under the old definition to be deserialized correctly under the new definition. Forward compatibility is not supported in this particular example. For an example of a class that supports both backward and forward compatibility, see matlab.mixin.CustomElementSerialization.

Customize Serialization in Both Superclasses and Subclasses

Some class revisions require changes to the serialization or deserialization process in both the superclass and a subclass, and the order of those changes can be important. In this example, change the datetime display format of the TimeStamps property from "MMMM d, yyyy HH:mm:ss" to "dd-MMM-uuuu HH:mm". To apply this format change to TempData but not the other subclasses of SensorData, make the change in TempData.

Create an instance of TempData using the first version of the class.

t2 = TempData;
t2.Data = [18 18 17 18];
t2.Interval = minutes(30);
t2.Location = "NW Building 1"
t2 = 

  TempData with properties:

        Units: "C"
         Data: [18 18 17 18]
    StartTime: June 19, 2024 00:00:00
     Interval: 30 min
     Location: "NW Building 1"

Save t2 and then clear the instance.

save("yourfilepath/SensorTest2.mat","t2")
clear t2

Update the second version of the TempData class. The modifyIncomingSerializationContent method must first call the superclass method and then apply the format change to the newly created TimeStamps property.

classdef TempData < SensorData
    properties
        Units {mustBeMember(Units,["F","C"])} = "C"
    end
    methods (Static)
        function modifyIncomingSerializationContent(sObj)
            if ~sObj.hasNameValue("TimeStamps")
                modifyIncomingSerializationContent@SensorData(sObj);
            end
            sObj.TimeStamps = datetime(sObj.TimeStamps,Format="dd-MMM-uuuu HH:mm");
        end
    end
end

Load the instance t2 under the latest definitions of SensorData and TempData. The superclass method adds the TimeStamps property, and the subclass method reformats the data in TimeStamps.

load("yourfilepath/SensorTest2.mat","t2")
t2
t2 = 

  TempData with properties:

         Units: "C"
          Data: [18 18 17 18]
    TimeStamps: [19-Jun-2024 00:00    19-Jun-2024 00:30    19-Jun-2024 01:00    19-Jun-2024 01:30]
     StartTime: June 19, 2024 00:00:00
      Interval: 30 min
      Location: "NW Building 1"

See Also

| |

Related Topics