Extended RIM JDE API has very powerful feature – Persistent objects. This allows you just to mark any class as “implements Persistable” and be able to hibernate any instance of this class to internal BB Persistent storage using net.rim.device.api.system.PersistentObject class.
That’s cool, but there are some restrictions. As soon as you modify you class in future program updates including private members changes, all persistent information will be lost. This is because of saved information is no more matching the new class structure.
Not so bad news at first look, but according to the best practice of storing objects (see an article) we need to group objects into a single collection. And in case of changes in any object that is stored in such collection, all the collection will be invalidated and lost!
So what do do? How to save information between application updates? In my project I decided to implement custom serialization approach using PersistentObject and collection of predefined types that will not be changed.
Let’s say class Person has 3 properties:
- String FirstName;
- String LastName;
- Integer Age;
As soon as String and Integer are types that not to be changed in future updates we can serialize Person as a Vector of FirstName, LasttName, Age values. I prefer to use Hashtable against Vector, so that we can easily get properties by key but not position. This is important when we do not know how old was version of app that saved this information and we cannot replay on properties indexes.
As soon as Hashtable does not implement Persistable interface I used Custom class PHashtable as a wrapper of Persistable class LongHashtable with custom translation of String keys to long keys using StringUtilities.computeHashCode method.
Then I create a base object EntityBase which every new class should inherit in order to get ability to Persist it’s state. EntityBase has basic methods to Save and Delete itself and an Id property. All objects then will be placed into common PHashtable by their class name and then by their Id. So Id should be unique for every Class scope. One can simplify this mechanism not to use nested PHashtable objects but use complex keys like ClassName + “#” + Id, but I prefer this nesting to be able later get all objects of specific class.
Inheriting the EntityBase class will free us from routine work of implementing common serialization tasks of all classes. The only thing we need now is to implement 2 methods:
For our sample class listed above the implementation of these methods is:
public void setProperties(PHashtable properties) {
super.setProperties(properties);
FirstName = (String) properties.get("FirstName");
LastName = (String) properties.get("LastName");
Age = (Integer) properties.get("Age");
}
public PHashtable getProperties() {
PHashtable properties = super.getProperties();
properties.put("FirstName", FirstName);
properties.put("LastName", LastName);
properties.put("Age", Age);
return properties;
}
Implementing objects with properties of some other Persistent classes is less trivial but still simple. Let’s say we want to store information about person’s transport. So now in Person we have additional property Transport of class Car that extends EntityBase. We can use the samу Id for this Car object that we use for Person as soon as we require it to be unique only in class scope (Alternatively we can use some other calculated id like Id+”.Transport” or Id+”.Transport1″). And also we need to be sure that as soon as we save our Person to Persistens storage, the information abut it’s transport is also saved. And the same in case of Deleting the object.
So we are to implement 2 more methods:
public void Delete() {
Transport.Delete();
super.Delete();
}
public void Save() {
if (Transport != null) Transport.Save();
super.Save();
}
Also do not forget to load this this property from storage while Person initialization:
public Person(String Id) {
super(Id, true);
Transport = new Car(Id);
}
Heh. That’s all. As soon as new properties are added to the person class or removed. you do not need to worry. Only ensure that your getProperties method is ready to receive null while fetching property value.
If need ed you can also save some class version information or other metadata to properties collection to use it for more intelligent version migration mechanism. let’s say that you had CarModel and CarColor stored in Person class and then you moved it to separate property transport of class Car(Model, Color). Then you can ensure to fetch this information in Person’s getProperties method and populate Transport.Model and Transport.Color properties.
You can download see the code of a sample application with EntityBase class implementation and some usage example.
Looking forward to your comments and suggestions.
