I read this blog and this reference material and determined that the Spring Data Commons Domain Events does not work when applied within Spring Data REST AbstractRepositoryEventListener events (i.e., onBeforeSave, onAfterDelete, etc).
Person:
@Entity @Data @EqualsAndHashCode(callSuper=true)
public class Person extends AbstractEntity {
// impl
public void markComplete(){
registerEvent(new PersonCompletedEvent());
}
}
PersonCompletedEvent:
@Data public class PersonCompletedEvent {} // the RestBucks sample does not have OrderPaid event extend ApplicationEvent, I tried both ways and it still doesn't work.
Update: Read the comment in PersonHandler, it's the reason why application events do not work in this example.
PersonHandler:
@Component @RepositoryEventHandler public class PersonHandler {
@PersistenceContext private EntityManager entityManager;
@Autowired private PersonRepo personRepo;
@HandleBeforeSave public void beforeSave(Person afterPerson){
/* UPDATE ::: This is the problem.
* This line is the reason why applicatin events do not fire.
* I need the before entity to detect delta's in the domain
* so I must detach it. However this causes events to be dropped.
*
* What's the best way to get the previous state?
*/
entityManager.detach(afterPerson);
Person beforePerson = personRepo.findOne(afterPerson.getId());
// impl
if (some condition) {
afterPerson.markComplete(); // this does add the event but it's never fired.
}
}
}
AbstractEntity:
import org.springframework.data.domain.AbstractAggregateRoot;
@MappedSuperclass @Data @EntityListeners(AuditingEntityListener.class)
public abstract class AbstractEntity extends AbstractAggregateRoot implements Identifiable<Long> {
// impl
}
PersonListener:
public class PersonListener {
@EventListener
public void processCompleted(PersonCompletedEvent event) {
// THIS IS NEVER FIRED
}
}
I've debugged this extensively and it looks like the DomainEvents are getting dropped somewhere between RepositoryEntityController and EventPublishingRepositoryProxyPostProcessor$EventPublishingMethodInterceptor.
What's really happening is that a different instance of my Entity is actually being intercepted and at that point the DomainEvents are no longer there. I can confirm that @AfterDomainEventPublication clearDomainEvents() is NOT being called at this time which leads me to believe it has something to do with the domainEvents being transient.
Spring Data REST's RepositoryEntityController looks like this:
private ResponseEntity<ResourceSupport> saveAndReturn(Object domainObject, RepositoryInvoker invoker,
HttpMethod httpMethod, PersistentEntityResourceAssembler assembler, boolean returnBody) {
publisher.publishEvent(new BeforeSaveEvent(domainObject)); // 1
Object obj = invoker.invokeSave(domainObject); // 2
publisher.publishEvent(new AfterSaveEvent(obj));
After executing line commented with 1 my domainObject has domainEvents and that's what goes into the line commented with 2, invokeSave. When my breakpoint catches at RepositoryEntityController and EventPublishingRepositoryProxyPostProcessor$EventPublishingMethodInterceptor it's actually a different instance of my object (different object id) and the only thing missing is the domainEvents and nothing get's fired.
Update: Read my comment below, it's not working because the entity is detached.