Memento library
This library provides support for storing typed properties. Unlike java.util.Properties, it stores type information (it supportes most of the primitive types and arrays), and allows arranging the data in a hierarchy to express complex data structures. Thus it is more powerful than string-string mappings and ini files, but not so heavy-weight as databases.
Using
The library resides in the central Maven repository with group ID hu.kazocsaba and artifact ID memento. If you use a project management system which can fetch dependencies from there, you can just add the library as a dependency. E.g. in Maven:
<dependency>
<groupId>hu.kazocsaba</groupId>
<artifactId>memento</artifactId>
<version>1.0.0</version>
</dependency>
You can also browse the online javadoc.
Examples
Suppose we want to store instances of the following class:
class Person {
String name;
int age;
double iq;
}
Persistence can be implemented so:
void savePerson(Person person, Memento memento) {
memento.putString("name", person.name);
memento.putInt("age", person.age);
memento.putDouble("intelligence quotient", person.iq);
}
Person loadPerson(Memento memento) throws MementoFormatException {
Person person=new Person();
person.name=memento.getString("name");
person.age=memento.getInt("age");
person.iq=memento.getDouble("intelligence quotient");
return person;
}
Handling library evolution
If we update the data structure with an additional method, we can still load mementos saved in the previous version if we handle the missing property:
class Person {
String name;
int age;
double iq;
String language;
}
void savePerson(Person person, Memento memento) {
memento.putString("name", person.name);
memento.putInt("age", person.age);
memento.putDouble("intelligence quotient", person.iq);
}
Person loadPerson(Memento memento) throws MementoFormatException {
Person person=new Person();
person.name=memento.getString("name");
person.age=memento.getInt("age");
person.iq=memento.getDouble("intelligence quotient");
// if we can supply a default value:
person.language=memento.getString("language", "English");
// otherwise check if the property is missing and handle it
if (memento.hasProperty("language")) {
person.language=memento.getString("language");
} else {
// handle missing property
}
return person;
}
Complex data structures
Now suppose that we want to represent children of people too:
class Person {
String name;
int age;
double iq;
List<Person> children;
}
void savePerson(Person person, Memento memento) {
memento.putString("name", person.name);
memento.putInt("age", person.age);
memento.putDouble("intelligence quotient", person.iq);
for (Person child: person.children)
savePerson(child, memento.createChild());
}
Person loadPerson(Memento memento) throws MementoFormatException {
Person person=new Person();
person.name=memento.getString("name");
person.age=memento.getInt("age");
person.iq=memento.getDouble("intelligence quotient");
for (Memento childMemento: memento) {
Person child=loadPerson(childMemento);
person.children.add(child);
}
return person;
}
If a memento needs to have multiple child mementos of different kinds, a string can be used to identify the different memento types:
void savePerson(Person person, Memento memento) {
// ...
for (Person child: person.children)
savePerson(child, memento.createChild("child"));
for (Account account: person.accounts)
savePerson(child, memento.createChild("account"));
}
Person loadPerson(Memento memento) throws MementoFormatException {
// ...
for (Memento childMemento: memento) {
if ("child".equals(childMemento.getType())) {
// read and add child
} else if ("account".equals(childMemento.getType())) {
// read and add account details
}
}
return person;
}