1

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.

szxnyc
  • 2,495
  • 5
  • 35
  • 46
  • What is the actual question? – Jens Schauder Aug 07 '17 at 05:33
  • @JensSchauder, I know I'm a bit vague in this post but the general question / problem is that the Spring Application Event's are not firing in this example and I found the root problem (I've updated this post to reflect that). I need to detect state changes with my entity's because that drives business logic and the only way I see to get the before entity here is to detach it from the persistence context...but by doing so the events won't fire. I think I need to take a completely different approach to this. – szxnyc Aug 07 '17 at 20:40
  • It's not that it is vague. To be honest it is messy. I'd recommend rewriting the complete question and give it some clear structure: What do you do; What do you expect; What does happen; What is the actual question (bold, ending in a question mark); All relevant source code; Bonus points for a link to a repo on which one can run mvn clean install and gets a test failure. – Jens Schauder Aug 08 '17 at 05:45
  • Regarding this question: What's the best way to get the previous state? This issue might be of interest: https://jira.spring.io/browse/DATAREST-373 – Jens Schauder Aug 08 '17 at 05:48

0 Answers0