8

I've got a @RepositoryEventHandler set up and it is not being invoked for some unknown reason.

@Component
@RepositoryEventHandler(User.class)
public class UserEventHandler {

    @Autowired
    private PasswordCrypto passwordCrypto;

    @HandleBeforeSave
    public void handleUserSave(User user) {
        if (user.getPassword() != null && !"".equals(user.getPassword())) {
            user.setPassword(passwordCrypto.encrypt(user.getPassword()));
        }
    }

    @HandleBeforeCreate
    public void handleUserCreate(User user) {
        user.setPassword(passwordCrypto.encrypt(user.getPassword()));
    }
}

The Repository:

public interface UserRepository extends CrudRepository<User, Long> {
    Optional<User> findOneByUsername(String username);
}

And my main class:

@SpringBootApplication
@EntityScan("de.ihrig.feuerwehr.hydranet.model")
@EnableJpaRepositories
@ComponentScan({
    "somepath",
    "somepath including the UserEventHandler"
})
public class ServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ServerApplication.class, args);
    }
}

Thanks for your help in advance, I just cannot find the error.

Jens Schauder
  • 77,657
  • 34
  • 181
  • 348
Benny
  • 1,435
  • 1
  • 15
  • 33
  • Please can you clairfy what you mean by not working ? How are you invoking your rest service ? The same set up works for me, I believe the problem might lie in how you conclude that it is not working. – ArunM Sep 27 '15 at 06:53
  • 17
    OK, I think I missunderstood the concept of @RepositoryEventHandler. It is called on the HTTP Requests done to the Data-REST exposed repositories, but not when you use any repository-method programmatically, which is what I did. The naming of the annotation is missleading somehow... – Benny Sep 28 '15 at 11:21
  • ^^ I think that is your answer. – Matthew Payne Mar 04 '16 at 01:05
  • Is there a way to listen to repository changes done programmatically? – AlikElzin-kilaka Feb 22 '18 at 18:00
  • 1
    You can just use JPA callbacks for this like `@PrePersist` if you use annotations. – Benny Feb 23 '18 at 05:58

1 Answers1

2

There could be a couple of things going on.

You're repo isn't annotated w/ @RestResource, but I'm guess that was just an oversight.

I'm guessing the comments are correct and you're testing this through a unit test with an entry point that is not going through the REST API. The handlers only capture Repo events that are coming through that vector.

If you want to capture any repo event, regardless of entry point, then you want to use a AbstractRepositoryEventListener

The Spring Data Rest Events documentation covers this. Also see listening for repository events in spring boot.

Community
  • 1
  • 1
Snekse
  • 15,474
  • 10
  • 62
  • 77
  • Oh, and this: http://stackoverflow.com/questions/4895854/jpa-postpersist-postupdate-transaction – Snekse Jan 08 '17 at 18:44
  • 3
    _"If you want to capture any repo event, regardless of entry point, then you want to use a AbstractRepositoryEventListener"_ <-- I am not so sure. I just tested this and made an AbstractRepositoryEventListener. It is indeed triggering for my REST calls but not in my CommandLineRunner class where I initially insert some data into my database using repositories. The fact the class is in the package org.springframework.data.rest.core.event also makes it questionable. – Sebastiaan van den Broek Feb 20 '18 at 03:24
  • 1
    @SebastiaanvandenBroek I think you're right. The docs are for SDR and they clearly state "_There are eight different events that the REST exporter emits _" so that indicates the events are only triggered via SPR. Another option might be to use [Spring Data JPA Auditing hooks](http://www.baeldung.com/database-auditing-jpa) for `AuditingEntityListener` & `@Pre/@Post` annotations, but I'm not sure what baggage that might introduce. – Snekse Feb 20 '18 at 18:37
  • I'm thinking you would have to intercept the call somehow, determine if it was called via the REST API or not, if it wasn't, then publish a `BeforeSaveEvent` but based on my experience w/ SDR, that seems like a dangerous proposition. A better way might be to have an application event listener that decorates the created repo bean w/ the funcs that `UserEventHandler` is already doing. Or go the easy route, and override `setPassword` to always encrypt immediately. – Snekse Feb 20 '18 at 18:57
  • I’m not the OP, I needed to hook into this event for another reason, but it’s not super critical in my case, I can work around it. I’ll have a look at those options though, thanks. – Sebastiaan van den Broek Feb 20 '18 at 19:00