To create a class of Base objects that supports persistence and
      that can be stored and restored using the
      SaveBase and LoadBase
      modules (see Section 8.2, “Composing, Storing and Retrieving Base Objects”), the following
      steps can be taken (this is an alternative to the TreeNode persistence mechanism):
Derive your custom class from Base or
            another class derived from Base (
              Section 2.1.2.3, “Base Field”
            ).
Include 
              mlAbstractPersistenceStream.h
             in your header
            file.
Overwrite the virtual methods
            writeTo() and
            readFrom().
Overwrite the virtual method
            implementsPersistence() to return true for the persistence interface(s) that you implement. This is a new requirement so that other instances can decide which persistence interface to use.
Assign a version number to your class by using the macro
            ML_SET_ADDSTATE_VERSION(VersionNumber) in
            your public class header.
This is the same as in the TreeNode interface
Add the ML_CLASS_HEADER(ClassName)
            macro in the header.
Add the ML_CLASS_SOURCE(ClassName, SuperClassName) macro in the cpp.
Call YourClass::initClass() in the
            project's init.cpp file.
The following example shows how to implement persistence to a
      simple class SegmentedObject. The class
      SegmentedObject is derived from
      BaseItem which is derived from
      Base:
Base (abstract class, no members)
     |
BaseItem (name, id)
     |
SegmentedObject (objectGrayValue, voxelCount, boundingBox)Example 8.2. How to Implement Persistence for Base Objects
Header file of a class
        SegmentedObject:
class SegmentedObject : public BaseItem {
...
public:
      //! announce supported persistence interfaces
      virtual bool implementsPersistence(PersistenceInterface iface) const
      {
          return (iface == PersistenceByStream);
      }
      //! Implement export functionality (as used by the SaveBase module):
      virtual void writeTo(AbstractPersistenceOutputStream* stream) const;
      // Set current version number
      ML_SET_ADDSTATE_VERSION(1);
      //! Implement import functionality (as used by the LoadBase module):
      virtual void readFrom(AbstractPersistenceInputStream* stream, int version);
private:
      //! ML runtime system related stuff
      ML_CLASS_HEADER(SegmentedObject);
      // Members to be (re-)stored:
      //! The identifying gray value of this object
      long _objectGrayValue;
      //! Number of voxels
      long _voxelCount;
      //! Bounding box respective to original image
      SubImageBox* _boundingBox;
...
}Source file of class
      SegmentedObject:
Writing the object state to the stream:
//! Implement export functionality:
void SegmentedObject::writeTo(AbstractPersistenceOutputStream* stream) const
{
  // Add superclass members:
  ML_WRITETO_SUPER(BaseItem, stream);
  // Add this class' members:
  stream->write(_objectGrayValue, "ObjectGrayValue");
  stream->write(_voxelCount, "VoxelCount");
  // The bounding box is optional, do not write if the pointer is NULL:
  if (_boundingBox) {
    // start a new sub-structure
    stream->startStruct("BoundingBox");
    stream->write(_boundingBox->v1, "v1");
    stream->write(_boundingBox->v2, "v2");
    stream->endStruct();
  }
}Reading the object state from the stream:
//! Implement import functionality:
void SegmentedObject::readFrom(AbstractPersistenceInputStream* stream, int version)
{
  // Read super class members:
  ML_READFROM_SUPER(BaseItem, stream);
  // Handle version differences:
  // In this example, version 0 used a different tag for _objectGrayValue
  // and did not write the VoxelCount value.
  switch (version) {
    case 0 :
      // Read object gray value from old tag name
      parent->read(_objectGrayValue, "GrayValue");
      break;
    case 1 :
      parent->read(_objectGrayValue, "ObjectGrayValue");
      break;
    default:
      // Throw exception: A version upgrade was performed without adapting the version handling
      // Note that this exception only needs to be thrown if you want to be on the safe side.
      // The persistence framework outputs a warning on its own if a newer version than that
      // from ML_SET_ADDSTATE_VERSION is encountered.
      throw PersistenceStreamFormatException("Unsupported version");
  }
  // Handle version difference (voxelCount available or not)
  // by calling the macro readOptional which sets
  // the given variable to a default value (second parameter)
  // in case the tag "VoxelCount" was not found.
  stream->readOptional(_voxelCount, 0, "VoxelCount");
  // Bounding box is optional:
  // However, startStruct can not be called optionally,
  // hence we have to check beforehand if there is an element with the correct name:
  if (stream->isNextInStruct("BoundingBox")) {
    try {
      ML_CHECK_NEW(_boundingBox, new SubImageBox());
      stream->startStruct("BoundingBox");
      stream->read(_boundingBox->v1, "v1");
      stream->read(_boundingBox->v2, "v2");
      stream->endStruct()
    }
    catch (const PersistenceStreamException& e) {
      // make sure to delete bounding box again:
      ML_DELETE(_boundingBox);
      // re-throw exception
      throw;
    }
  }
}Registering the class in the runtime type system:
ML_CLASS_SOURCE(SegmentedObject, BaseItem)
          © 2025 MeVis Medical Solutions AG