Use event interface in entity class
The current event model requests the creation of a bean component to implement the child AbstractRelationalEvent (AfterSaveEvent / BeforeConvertEvent / ...)
If the event logic is strongly related to the entity, then now you have to divide them into classes, perhaps make some private attributes public.
You can add processing logic if the entity itself implements these interfaces. Do not publish the event (or with publish), but call the method on the entity If the event model will check the implementation of the interface and call it instead of or together with sending the event, then it will be possible to combine the entity and its reaction to events in one class
for example something like this:
package org.springframework.data.jdbc.core;
...
public class JdbcAggregateTemplate implements JdbcAggregateOperations {
...
private <T> T triggerBeforeConvert(T aggregateRoot) {
if (aggregateRoot instanceof BeforeConvertCallback) {
return ((BeforeConvertCallback<T>) aggregateRoot).onBeforeConvert(aggregateRoot);
}
eventDelegate.publishEvent(() -> new BeforeConvertEvent<>(aggregateRoot));
return entityCallbacks.callback(BeforeConvertCallback.class, aggregateRoot);
}
hello! could i work on?
Sure.
hello i have question.
according to example
private <T> T triggerBeforeConvert(T aggregateRoot) {
if (aggregateRoot instanceof BeforeConvertCallback) { // new
return ((BeforeConvertCallback<T>) aggregateRoot).onBeforeConvert(aggregateRoot);
}
eventDelegate.publishEvent(() -> new BeforeConvertEvent<>(aggregateRoot)); // previously existing code
return entityCallbacks.callback(BeforeConvertCallback.class, aggregateRoot);
}
if (aggregateRoot instanceof BeforeConvertCallback) is true previously existing code is not excuted is this the right design? or would it be better to allow the existing code to run as well? in my opinion, event should still be published through eventDelegate
like below
private <T> T triggerBeforeConvert(T aggregateRoot) {
eventDelegate.publishEvent(() -> new BeforeConvertEvent<>(aggregateRoot));
if (aggregateRoot instanceof BeforeConvertCallback) {
return ((BeforeConvertCallback<T>) aggregateRoot).onBeforeConvert(aggregateRoot);
}
return entityCallbacks.callback(BeforeConvertCallback.class, aggregateRoot);
}
events and callbacks should still get triggered/called.
And either all before the aggregate root or all after, but certainly not some before some after.
Actually it probably should just use the callback mechanism, so ordering can be controlled in the usual ways.
hi !
if an entity directly implements a callback interface, it should also be included in the entityCallbacks?
Yes. Basically the entity becomes just another callback implementation.
hello. thank for quick response !
Ultimately, the design needs to satisfy these requirements:
-
Callback implemented in the entity class must be treated the same way as other callbacks registered in EntityCallbacks, including participating in the same ordering mechanism.
-
Callback implemented in the entity class must be able to access the entity’s private methods and fields.
I plan to register the following object in advance for each entity that implements an entity callback.
Is there a better approach, or are there any issues with this approach?
public final class DelegatingBeforeSaveCallback<T>
implements BeforeSaveCallback<T>, Ordered {
private final int order;
public DelegatingBeforeSaveCallback(int order) {
this.order = order;
}
@Override
public int getOrder() {
return order;
}
@Override
@SuppressWarnings({"unchecked", "rawtypes"})
public T onBeforeSave(T aggregate, MutableAggregateChange<T> aggregateChange) {
if (aggregate instanceof BeforeSaveCallback rawCallback) {
return (T) rawCallback.onBeforeSave(aggregate, aggregateChange);
}
return aggregate;
}
}