Today, I want to introduce a simple Memento implementation.
It's simple and easy to use. No cast from Object here, not null comparison there, pure, beautiful Java 5 with annotations in foreground (and reflection in the background, pssst!)
In my main project, I'm using action queues. There are a lot of possible failures during a processing of a such queue, but only one successful state (at the end). I needed a possibility to restore the initial state of all involved objects, whose state has been changed. So I started three or four different (classic) approaches (just generic classes and interfaces), but none of them was elegant and simple enough, to fit my 'requirements'. I found no possibility to enforce type strictness.
As a last chance, I tried to declare a custom annotation and create a class which represents the 'memento', the state manager of objects.
First, I show you how to use the annotation:
public class StatefulObject
implements IStateful {
@Stateful
protected String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void afterRestoreState() {
// in our case, do nothing
}
}
Here, the field "name" is declared to be related to the state of our object.
Following code demonstrates, how to store / retrieve states:
StatefulObject o1 = new StatefulObject();
Memento<StatefulObject> m =
new Memento<StatefulObject>(StatefulObject.class);
o1.setName("old");
m.addNewState(o1); // save the state
o1.setName("new");
m.restoreInitialState(o1); // restore the state (name is back to "old")
To make this possible, we need an container (memento) which stores the states of the objects. It's lot of (mostly trivial) code.
In words: you traverse an class' fields using java reflection (this is done once in the constructor). To store and restore states, you use an Object[] array. To make the memento work as a stack you could use Stack<Object[]>.
Important note: there is a conceptional problem with "@Stateful" fields: when they're restored, they get overwritten. That means: references to such fields become invalid! Some abc==someStatefulField comparisons will be invalidated this way. Keep that in mind!