Navigation:  Programming Cookbook > Binary Filing Objects >

Converting STB data after instance layout changes

Previous pageReturn to chapter overviewNext page

This can be a difficult job so it is worth stating right at the start that if you never rely on old STB data then you don't need to bother yourself with STB conversion issues!

When an object's data is written to the stream, its instance variables are written out in the order they appear in its definition, followed by any indexed variables. If the order or number of instance variables is changed then STB data stored before the change will either have the wrong meaning in a new instance, will not fit a new instance or both. Loading old-format instances is possible using the STB versioning mechanism.

All object data is prefixed by a reference to its basic class credentials including the STB version number of the class when the data was written. If a class undergoes a change in its format and it is necessary to load its old format from STB data then you need to write a conversion method to translate the old data to the new format or indeed to an instance of some other class.

You need to make essentially two changes:

1.Increment the STB version number of the class
2.Provide a conversion method to translate the layout

Override the class method #stbVersion to answer the new format version number. By default this method answers 0 so for a first change a new version number of 1 is required - be careful to ascertain the impact of the version number on subclasses.

Then you need to provide/amend the #stbConvertFrom: class method which is passed an instance of STBClassFormat describing the format and version number of the old object. This method should answer nil if it can't convert from the version identified causing the STBInFiler to signal an STBError.

The method should answer a monadic valuable (generally a block) that answers a new, current format instance initialized from the old data. It is important that the block answer a new object because the STBInFiler uses #become: to swap the temporary old data object with the new object. The old data is represented by an Array or ByteArray passed as the block's single parameter. You can calculate the basicSize (indexed size) of the old object by querying STBClassFormat>>#instSize.

Where several version changes occur it may be advisable to re-use previous converters using the following technique.

stbConvertFrom: anSTBClassFormat

  "Private - Answer a block to convert the given data array to

  an instance of the current version."

  | selector array newInstance |

  ^[:data |

  array := data.

  anSTBClassFormat version to: self stbVersion - 1 do: [:version |

      selector := ('convertFromVersion', version asString, ':') asSymbol.

      array := self perform: selector with: array].

  newInstance := self basicNew.

  1 to: self instSize do: [:i |

      newInstance instVarAt: i put: (array at: i)].

  newInstance]

 

Note that the old object could be replaced by an object of an entirely different class.