Main Content

Maintain Backward and Forward Compatibility Between Class Definitions

Revising a class definition can lead to errors when trying to deserialize instances of a different version of that class using the default load process. When changing a class definition, you can inherit from matlab.mixin.CustomElementSerialization and use it to control how the new class definition serializes and deserializes instances to preserve compatibility. The general process is:

  • When you revise your class definition in a way that breaks compatibility with the older version, add matlab.mixin.CustomElementSerialization as a superclass.

  • If you need to change how objects of the revised class are serialized, implement the modifyOutgoingSerializationContent method of matlab.mixin.CustomElementSerialization. The method takes an instance of matlab.serialization.ElementSerializationContent as input. That object represents what will be serialized, and the methods of matlab.serialization.ElementSerializationContent enable you to change how properties are serialized.

  • If you need to change how objects of the revised class are deserialized, implement the modifyIncomingSerializationContent method of matlab.mixin.CustomElementSerialization. The method takes an instance of the matlab.serialization.ElementSerializationContent class as input. That object represents what will be deserialized, and the methods of matlab.serialization.ElementSerializationContent enable you to change how properties are deserialized.

  • If you need to perform any final operations on the deserialized object, such as adding an event listener, implement the finalizeIncomingObject method of matlab.mixin.CustomElementSerialization. The method takes the deserialized object as input.

Backward Compatibility

Define a class Employee that stores basic information. The EmployeeID property is stored as a string with "ID-" at the beginning, as shown by the default value.

classdef Employee
    properties
        Name
        Department
        EmployeeID = "ID-0000"
        Email
    end
end

Create an instance of Employee, assign values to all the properties, and save it. Replace yourfilepath with your local path.

eOld = Employee;
eOld.Name = "Alex Cruz";
eOld.Department = "Sales";
eOld.EmployeeID = "ID-1301"
eOld.Email = "acruz@notacompany.com"
save("yourfilepath/oldEmployee.mat","eOld");

Update the class definition with new and redefined properties:

  • Split Name into FirstName and LastName.

  • Change Department to Division.

  • Remove the "ID-" prefix from the EmployeeID property.

Trying to deserialize an object that was serialized under the old definition would leave some properties without proper values. To keep the old objects as accessible as possible, add matlab.mixin.CustomElementSerialization as a superclass and implement the static method modifyIncomingSerialization to convert the old property data into the new format as needed.

classdef Employee < matlab.mixin.CustomElementSerialization
    properties
        LastName
        FirstName
        EmployeeID
        Division
        Email
    end
   methods (Static)
        function modifyIncomingSerializationContent(sObj)
            if sObj.hasNameValue("Name")
                nameArray = split(sObj.Name);
                sObj.addNameValue("FirstName",nameArray(1));
                sObj.addNameValue("LastName",nameArray(2));
                sObj.remove("Name");
                sObj.rename("Department","Division");
                id = split(sObj.EmployeeID,"-");
                sObj.updateValue("EmployeeID",id(2));
            end
        end
   end
end

MATLAB® calls modifyIncomingSerializationContent when you load an object of Employee. The method takes as input an instance of matlab.serialization.ElementSerializationContent. The hasNameValue method of matlab.serialization.ElementSerializationContent checks to see if the saved object has a property called Name. If there is a Name property, the object being deserialized was serialized under the old class definition. In that case, the methods of matlab.serialization.ElementSerializationContent convert and assign the old property data into the revised properties:

  • The value of the Name property is split into an array of two strings, and the addNameValue method adds the FirstName and LastName properties. remove discards the old property Name.

  • The rename method changes Department to Division.

  • The updateValue method changes the value of the EmployeeID property to include only the numeric portion.

Clear eOld from memory.

clear("eOld")
Remove the old definition of Employee from your path. Add the revised definition of Employee to the path, and load the eOld object. Display the object to confirm that the variable has been deserialized as an object of the revised definition of Employee.

load("yourfilepath/oldEmployee.mat","eOld")
eOld
eOld = 

  Employee with properties:

      LastName: "Cruz"
     FirstName: "Alex"
    EmployeeID: "1301"
      Division: "Sales"
         Email: "acruz@notacompany.com"

matlab.mixin.CustomElementSerialization also provides a static finalizeIncomingObject method. If the method is implemented, MATLAB calls it after modifyIncomingSerializationContent. Use the method to perform any necessary cleanup on the deserialized object, like restoring property listeners, for example. In the case of Employee, finalizeIncomingObject could be used to fill in the unknown value for EmployeeID if the method has access to that data from other sources.

The modifyOutgoingSerializationContent method also has an optional input argument, an instance of matlab.serialization.SerializationContext. An instance of this class can be used to determine the context in which the object is being serialized. For example, MATLAB sets the CustomizeForReadability property of the instance to true if the serialized object is readable by external users.

For an additional example on preserving backward compatibility, see Load Serialized Objects After Changing Class Definition.

Forward Compatibility

The latest version of Employee can now successfully deserialize objects saved under the older version of the class, but the class does not have forward compatibility. In other words, someone who only has access to the older version of the class cannot successfully deserialize an object serialized under the latest version of the class.

To support forward compatibility, implement the modifyOutgoingSerializationContent method of matlab.mixin.CustomElementSerialization in the new class definition. This method controls what information is serialized, so the goal is to save the information in a way that both the old and new versions of the class can access.

MATLAB calls modifyOutgoingSerializationContent when you save an object of Employee. The method takes as inputs an object of matlab.serialization.ElementSerializationContent as well as the object itself. The process from there is the inverse of how modifyIncomingSerializationContent works. The properties are reverted to the format of the older version so that the data can be deserialized by either version of the class.

classdef Employee < matlab.mixin.CustomElementSerialization
    properties
        LastName
        FirstName
        EmployeeID = "0000"
        Division
        Email
    end
    methods (Static)
        function modifyIncomingSerializationContent(sObj)
            if sObj.hasNameValue("Name")
                nameArray = split(sObj.Name);
                sObj.addNameValue("FirstName",nameArray(1));
                sObj.addNameValue("LastName",nameArray(2));
                sObj.remove("Name");
                sObj.rename("Department","Division");
                id = split(sObj.EmployeeID,"-");
                sObj.updateValue("EmployeeID",id(2));
            end
        end
        function modifyOutgoingSerializationContent(sObj,obj)
            nameStr = append(obj.FirstName," ",obj.LastName);
            sObj.addNameValue("Name",nameStr);
            sObj.remove("FirstName");
            sObj.remove("LastName");
            sObj.rename("Division","Department");
            fullID = append("ID-",obj.EmployeeID);
            sObj.updateValue("EmployeeID",fullID);
        end
     end
end

Resave eOld under the newer definition of Employee and then load it under the older class definition. The deserialized version under the older definition is in the correct format.

eOld = 

  Employee with properties:

          Name: "Alex Cruz"
    Department: "Sales"
    EmployeeID: "ID-1301"
         Email: "acruz@notacompany.com"

For another example of a revised class definition that supports both forward and backward compatibility, see Maintain Backward and Forward Compatibility During Serialization.

See Also

| |

Related Topics