Community contributed extensions

Lifecycle event model of PlayMorphia and Morphia

The content of this chapter is only valid for PlayMorphia v1.2.4 or later.

In this chapter we will explorer the lifecycle event model of PlayMorphia (start from v1.2.4) and Morphia.

Create events

PlayMorphia create events

eventdescription
on addtriggered before an new entity is saved
addedtriggered after an new entity is saved

Event implementation

eventannotationinterface
on add@OnAddIMorphiaEventHandler.onAdd(Model)
added@AddedIMorphiaEventHandler.added(Model)

Morphia create events

Morphia does not provide specific create events, however you could use PrePersist, PreSave and PostPerist to simulate create events and use this.isNew() to identify if current model instance is an new entity or existing entity. See Morphia update events for detail about PrePersist, PreSave and PostPerist events.

Update events

PlayMorphia update events

eventdescription
on updatetriggered before an existing entity is saved
updatedtriggered after an existing entity is saved

Event implementation

eventannotation 1interface 2
on update@OnUpdateIMorphiaEventHandler.onUpdate(Model)
updated@UpdatedIMorphiaEventHandler.updated(Model)

1 see more about annotation based PlayMorphia lifecycle event handling

2 see more about event handler based PlayMorphia lifecycle event handling

Morphia update events

eventannotationdescription
pre persist@PrePersisttriggered before a PlayMorphia model instance get converted into a MongoDB’s DBObject
pre save@PreSavetriggered after a PlayMorphia model instance get converted into a MongoDB’s DBObject and before that DBObject is saved into MongoDB
post persist@PostPersisttriggered after the model instance saved into MongoDB

Morphia annotation enable you do define methods that accept parameters and return result. Click here for examples.

Load events

PlayMorphia load events

eventdescription
on loadtriggered before an entity is loaded from MongoDB
loadedtriggered after an entity is loaded from MongoDB

OnLoad event is seldom used as when this event triggered, the entity is still empty and waiting for the fields to be filled

Event implementation

eventannotationinterface
on load@OnLoadIMorphiaEventHandler.onLoad(Model)
loaded@LoadedIMorphiaEventHandler.loaded(Model)

Morphia load events

eventannotationdescription
pre load@PreLoadtriggered before a PlayMorphia model instance get loaded from MongoDB
post load@PostLoadtriggered after the model instance loaded from MongoDB

Delete events

PlayMorphia delete events

eventdescription
on deletetriggered before an entity is removed from MongoDB
deletedtriggered after an entity deleted from MongoDB

Event implementation

eventannotationinterface
on delete@OnDeleteIMorphiaEventHandler.onDelete(Model)
deleted@DeletedIMorphiaEventHandler.deleted(Model)

Morphia delete events

Morphia does not support delete events

Batch delete events

PlayMorphia batch delete events

eventdescription
on batch deletetriggered before a set of entities defined by a PlayMorphia query removed from MongoDB
batch deletedtriggered after a set of entities defined by a PlayMorphia query deleted from MongoDB

Event implementation

eventannotationinterface
on batch delete@OnBatchDeleteIMorphiaEventHandler.onBatchDelete(MorphiaQuery)
batch deleted@BatchDeletedIMorphiaEventHandler.batchDeleted(MorphaQuery)

Morphia batch delete events

Morphia does not support batch delete events

Additional notes

PlayMorphia annotated lifecycle event handler signature

No return object and method parameters should be defined for the following annotation based event handler: @OnLoad, @Loaded, @OnAdd, @Added, @OnUpdate, @Updated, @OnDelete, @Deleted:

@Entity MyMode extends Model {
    // correct signature 
    @OnLoad void onLoad() {}
    @Loaded void loaded() {}
    @OnAdd void onAdd() {}
    @Added void added() {}
    @OnUpdate void onUpdate() {}
    @Updated void updated() {}
    @OnDelete void onDelete() {}
    @Deleted void deleted() {}
    // the following method's signatures are not correct and they will not be triggered at all
    @OnLoad Model myOnLoad() {...}
    @Loaded void myLoaded(String xx) {...}
    @OnAdd String myOnAdd(Model xx) {...}
}

You could make those methods static or non-static, but it’s highly recommend to use non-static methods for the above event handling as you get the access to the entity which is experiencing the lifecycle events via “this” pointer.

There is completely no requirements on method scope, you can make it either one of “public”, “protected”, “private” or default package level, the functionality will not impact by changing the method scope.

Unlike the above events, the two batch events (@OnBatchDelete and @BatchDeleted) have a bit different method signature:

@Entity MyModel extends Model {
    @OnBatchDelete static void onBatchDelete(MorphiaQuery q) {...}
    @BatchDeleted static void BatchDeleted(MorphiaQuery q) {...}
}

As you could see, we have 2 differences in the batch event handler definition compare to that of the other event handlers:

  1. A MorphiaQuery type parameter is required. This is mandatory, otherwise your method will not be called when the batch delete event triggered.
  2. the batch event handling methods are defined as static methods. This is optional but recommended practice.

There are different method signature requirements when you are writing Morphia annotation marked lifecycle event handlers, please refer to this page for detail.

More on BatchDeleted event

A common error is to use the MorphiaQuery argument passed into BatchDeleted event handler to query for which models has been deleted. However that will always return an empty list as all those entities has been removed from MongoDB already. One way to get the deleted entities is to remember them in the OnBatchDelete event handler:

@Entity MyModel extends Model {
    private Map<MorphiaQuery, List<MyModel>> deleteModels_ = new HashMap<MorphiaQuery, List<MyModel>>();
    @OnBatchDelete static void onBatchDelete(MorphiaQuery q) {
        List<MyModel> list = q.asList();
        deleteModels_.put(q, list);
    }
    @BatchDeleted static void batchDeleted(MorphiaQuery q) {
        List<MyModel> list = deleteModels_.get(q);
        // do whatever you want on the deleted models
        ...
    }
}

Why do you prefer PlayMorphia event handling framework to Morphia one

  1. More clear. PlayMorphia events distiguish between add (new) and update (existing) entities while Morphia events don’t
  2. Performance. There are very little performance gain if you choose PlayMorphia event handling model. PlayMorphia code enhancer will burn the relevant code into final byte code so at runtime there is no reflection at all. While Morphia needs one time reflection for event handler call and then cache it to hash map for later on calls.
  3. More complete. PlayMorphia support delete and batch delete events while Mophia doesn’t.

Performance consideration

You are NOT required to do the same thing as shown in the above code. Calling to the event handler methods is executed in the current thread, the more logic you put into the event handlers the more performance is impact. So please do as simple as possible in any of the event handlers. Implement only the logic you need. If you don’t need to bother with batch delete events then you shouldn’t add batch delete event handler. Actually in most cases you don’t need to implement any lifecycle event handlers. This is ture for both PlayMorphia and Morphia event handling model.

See also

  1. Lifecycle handling introduction
  2. PlayMorphia model introduction
  3. Use of PlayMorphia model: crud