Serialize and deserialize LabVIEW classes using either JSONtext or TOML
Explore the docs »
This repository only houses the core for the framework. You first need to decide which type of serializer that you want to use. At the moment, the framework has the following supported serializers:
Text Type | VIP Name | VIP dependency |
---|---|---|
JSON | BlueJSONTextSerializer | JSONtext |
TOML | BlueTOMLSerializer | LV-TOML |
Installing one of these packages will pull down all of the dependencies that you need.
This script will behave differently depending on whether or not it's the first time that you have run this script against your class.
When this script finishes, you should see the following new files:
A few notes:
This script will allow for you to change your serializable data in a way that would normally create a backwards incompatible jump with respect to old serialized text.
When the script finishes, you should see the following new files in your project:
When the script finishes, you should see the following new files in your project:
A few notes:
This is a visualization tool and will not modify your class data or version in any manner. This menu item appears for all classes... This is not strictly a BlueSerializable.lvclass tool.
simple example:
Palette:
Category | Name | Default Value | Description |
---|---|---|---|
class slicing | slice objects per SetSerializeSliceClass.vi? | False | If True, then the wired object will be sliced to the class layer specified in the "SetSerializeSliceClass override. (No-op parent will not perform any slicing.) |
non-Blue | serialize non-BlueSerializable objects as hex? | False | If True, then non-BlueSerializable objects will be flattened as hex data using the LabVIEW "flatten to string" node. If false, an error will be returned when a non-BlueSerializable object is discovered |
Category | Name | Default Value | Description |
---|---|---|---|
expansion | expand objects on type conflict? | False | If True, then the wired object is allowed to be more-specific than the serialized text. The returned object will be the more specific object. If false, then an error will be returned in this situation. |
class slicing | slice flattened object data on error? | False | If True, then the framework will iterate upwards through a class hierarchy until it finds a load-able class instance. This means that the returned data may be less-specific than the serialized text. |
class slicing | sliceable class names | empty str array | If a class isn't found in memory, then the framework will be allowed to slice class names in this list until finding a class in the hierarchy that is load-able. |
non-Blue | deserialize non-BlueSerializable objects from hex? | False | If True, then the framework will unflatten non-BlueSerializable objects using the "unflatten from text" node. If False, then non-BlueSerializable objects found in the reference data will yield and error. |
Mutation | error on inserted parent levels? | False | If False, then the framework allows for class mutation history where a parent level was added. This means that your output data will contain default-data for this added class layer. If True, then error |
Mutation | error on obsolete parent levels? | False | If False, then the framework allows for class mutation history where a parent level was removed. This means that data for dropped class layers in your serialized text will also be unused. If True, then error. |
Data preservation | Preserve wired non-serialized data? | Don't Preserve | "Don't Preserve": non-serialized data will not be preserved. "Preserve (error on less-specific wired types)": non-serialized data will be preserved. However, if a wired object is found to be less specific than the serialized object, then you will receive an error. "Preserve (except on less-specific wired types)": non-serialized data will be preserved except where a wired object is found to be less specific than the serialized object. (It's not possible to preserve data in this situation without class composition.) |
If you're going to use this library, then it's important for you to understand what changes to a class will result in backwards incompatible breaks with respect to deserialization of old text. The following table documents all of this:
Change | Backwards compatible with old serialized text? | Backwards compatible with old software builds? |
---|---|---|
Parent class renamed | yes | no |
Parent class level added | yes | no |
Parent class level removed | yes | no |
Child or Parent class MAJOR version number incremented | yes | no |
Child class renamed | no | no |
class mutation history deleted | no | no |
Changes to serializable data | maybe | maybe |
Notes:
Observe that the Soccer Player class private data is Placeholder only.
This has 2 consequences:
A few notes about this behavior:
A few notes about this:
open-source libraries such as JSONtext, LV-TOML, and EasyXML have made it very easy to serialize and deserialize test to/from LabVIEW data structures. Unfortunately, none of these libraries support LabVIEW classes. As such, in order to use classes with these libraries, we used to have to be very careful not to include classes in serialized text, and then to have custom code for constructing/deconstructing objects from memory. What a pain!
Subgoals:
During research, we discovered 2 libraries out in the world that solve object serialization through the usage of object (de)composition:
"LogMAN" from the LAVA forum even went so far as to make available his reuse library for class (de)composition: https://lavag.org/topic/21894-openg-and-object-compatibility/?do=findComment&comment=134688
This code was written with direction from the LabVIEW wiki's extremely relevant wiki page:
https://labviewwiki.org/wiki/LabVIEW_Object
There are some Pros/Cons to this approach. Pros:
Cons:
In the figure below, observe that there exists a "SerializableData" cluster. A few notes about this:
There are some Pros/Cons to this approach: Pros:
Cons:
In the figure below, observe that we can switch between JSON and TOML serialization simply be swapping out the BlueSerializer class input:
At the moment, the following plug-in serializers are available:
Text Type | VIP Name | VIP dependency |
---|---|---|
JSON | BlueJSONTextSerializer | JSONtext |
TOML | BlueTOMLSerializer | LV-TOML |
However, the BlueSerialization core was written so that other users can easily add more serializer plug-ins to this list without modifying the core package. I hope to add XML to this list eventually.
BlueSerialization leverages a little-known feature of LabVIEW classes called "LabVIEW class mutation history". Mutation history primarily exists within LabVIEW to support the flattening and unflattening of a LabVIEW class to/from flattened text. Since this feature isn't well known or well documented, I'll document it a bit here:
Path |
---|
C:\Program Files (x86)\National Instruments\LabVIEW 2019\vi.lib\Utility\EditLVLibs\LVClass\Get Mutation History.vi |
C:\Program Files (x86)\National Instruments\LabVIEW 2019\vi.lib\Utility\EditLVLibs\LVClass\Set Mutation History.vi |
This typedef is, as shown below:
Field Name | Description |
---|---|
Library Version | This matches the LVClass version type. This resets to v1.0.0.0 when the fully qualified class name changes. |
Old Name Index | 0 == current name. This value changes each time that the fully qualified class name changes. This value, in conjunction with the Library Version, provides a unique key for finding a mutation history index. This value is directly related to the "Parent Old Name Index" value of descendant children classes. |
Class Default Data | A new class mutation history entry is created each time that a class' private data is modified. This entry provides a "snapshot" of the private data. Note that if a class private data contains typedefs or nested objects, that updates to these items will not create a new mutation history entry |
Cluster Order Map | This describes any reordering of elements in the private data. A value of 4294967294 indicates that order of an element has not changed. |
Parent Name | This contains the name of the Parent classes fully qualified name |
Parent Path | possibly unused? |
LabVIEW Version | HEX value displays the LabVIEW version |
User Comments | Basically a description field. BlueSerialization leverages this field for keeping track of a class's mutation version. Otherwise, to my knowledge, this field isn't used by LabVIEW internally. |
Mutation Flags | I have no idea |
Parent Old Name Index | This links to the "Old Name Index" of the parent class. This allows us to lookup the mutation index for a parent given the child's mutation history. |
Parent Levels Added | This indicates the number of parent levels added. A value of 0 indicates that no parent levels were added |
Parent Levels Removed | This indicates the number of parent levels removed. A value of 0 indicates that no parent levels were removed. A value of 65535 indicates that ALL parent levels were removed |
Distributed under the BSD-3 License. See LICENSE
for more information.