Object serialization#

Modules which have INCLUDE_MARSHAL in their vtk.module will opt their headers into the automated code generation of (de)serializers. Only classes which are annotated by the VTK_MARSHALAUTO wrapping hint will have generated serialization code.

Marshalling Hints#

Classes#

VTK auto generates (de)serialization code in C++ for classes annotated by the VTK_MARSHALAUTO wrapping hint. Additionally, classes that are annotated with VTK_MARSHALMANUAL require manual code. Please refer to manual-marshal-code which explains everything you need to consider when opting out of the automated marshalling code generation process.

Properties#

Excluding properties#

You can exclude certain properties of a class by simply annotating the relevant setter/getter functions with VTK_MARSHALEXCLUDE(reason), where reason is one of VTK_MARSHAL_EXCLUDE_REASON_IS_INTERNAL or VTK_MARSHAL_EXCLUDE_REASON_NOT_SUPPORTED. This reason will be printed in the generated C++ source code explaining why the property was not serialized.

Custom get/set functions#

Some properties may not be correctly recognized by the property parser because they have different names for their get and set functions. You can override this by annotating the get function with the VTK_MARSHALGETTER(property) macro. Doing so will ensure that the function gets recognized as a getter for property. VTK_MARSHALSETTER(property) serves a similar purpose.

Automated code generation#

The vtkWrapSerDes executable makes use of the WrappingTools package to automatically generate:

  1. A serializer function with signature:

    Note

    Generated only for classes annotated by VTK_MARSHALAUTO macro

    static nlohmann:json Serialize_vtkClassName(vtkObjectBase*, vtkSerializer*)
    
  2. A deserializer function with signature:

    Note

    Generated only for classes annotated by VTK_MARSHALAUTO macro

    static bool Deserialize_vtkClassName(const nlohmann::json&, vtkObjectBase*, vtkDeserializer*)
    
  3. A invoker function with signature:

    Note

    Generated for classes annotated by VTK_MARSHALAUTO or VTK_MARSHALMANUAL macro

    static nlohmann::json Invoke_vtkClassName(vtkInvoker* invoker, vtkObjectBase* objectBase, const char* methodName, nlohmann::json args)
    
  4. A registrar function that registers

    • the serializer function with a serializer instance

    • the deserializer function with a deserializer instance

    • the constructor of the VTK class with a deserializer instance

    • Here is an example for the class vtkObject:

      int RegisterHandlers_vtkObjectSerDes(void* ser, void* deser, void* invoker)
      {
        int success = 0;
        if (auto* asObjectBase = static_cast<vtkObjectBase*>(ser))
        {
          if (auto* serializer = vtkSerializer::SafeDownCast(asObjectBase))
          {
            serializer->RegisterHandler(typeid(vtkObject), Serialize_vtkObject);
            success = 1;
          }
        }
        if (auto* asObjectBase = static_cast<vtkObjectBase*>(deser))
        {
          if (auto* deserializer = vtkDeserializer::SafeDownCast(asObjectBase))
          {
            deserializer->RegisterHandler(typeid(vtkObject), Deserialize_vtkObject);
            deserializer->RegisterConstructor("vtkObject", []() { return vtkObject::New(); });
            success = 1;
          }
        }
        if (auto* asObjectBase = static_cast<vtkObjectBase*>(invoker))
        {
          if (auto* invokerObject = vtkDeserializer::SafeDownCast(asObjectBase))
          {
            invokerObject->RegisterHandler(typeid(vtkObject), Invoke_vtkObject);
            success = 1;
          }
        }
        return success;
      }
      

Manual marshal code#

On the other hand, the VTK_MARSHALMANUAL macro is used to indicate that a class will take part in marshalling, but it cannot trivially (de)serialize it’s properties. This is because one or more of the class’s properties may not have an appropriate setter/getter function that is recognized by the VTK property parser.

For such classes, a developer is expected to provide the code to serialize and deserialize the class in vtkClassNameSerDesHelper.cxx That file must satisfy these conditions:

  1. It must live in the same module as vtkClassName.

  2. It must export a function int RegisterHandlers_vtkClassNameSerDesHelper(void*, void*, void*) with C linkage.

  3. It must define and declare the static functions from automated-code-generation.

  4. Finally, it must implement the helper function RegisterHandlers_vtkClassNameSerDesHelper to register your handlers with the object manager. Please see the RegisterHandlers_vtkObjectSerDes sample code in automated-code-generation for guidance on implementing this helper.

Example:

int RegisterHandlers_vtkClassNameSerDesHelper(void* ser, void* deser, void* invoker)
{
  // See RegisterHandlers_vtkObjectSerDes for what must go here.
}

that registers:

  • a serializer function with a serializer instance

  • a deserializer function with a deserializer instance

  • a constructor of the VTK class with a deserializer instance

  • Optionally, a function that can call methods by name on an object with an invoker instance. The wrapping tool automatically generates this code even for classes annotated by VTK_MARSHALMANUAL. You can overwrite that in your custom RegisterHandlers_vtkClassNameSerDesHelper.

Marshal hint macro#

  1. Classes which are annotated with VTK_MARSHALAUTO are considered by the vtkWrapSerDes executable.

  2. Classes annotated with VTK_MARSHALMANUAL are hand coded in the same module. Here are some examples:

    • Common/Core/vtkCollectionSerDesHelper.cxx for Common/Core/vtkCollection.h

    • Common/DataModel/vtkCellArraySerDesHelper.cxx for Common/DataModel/vtkCellArray.h

Convenient script to annotate headers and module#

Testing serialization code#

Serialization testing can be run on top of regular VTK C++ regression tests by performing an image comparison test after serializing and deserializing the test’s render window. When VTK is configured with VTK_WRAP_SERIALIZAITON=ON, serialization tests will be generated with the suffix SerDes. Specific tests can be excluded from serialization testing by adding the NO_SERDES argument to the test in Some/Module/Testing/Cxx/CMakeLists.txt.