DATAREST-388 - Improved annotation based event handling.

The annotation based event handling now relies on the type of the first method argument to determine the domain type the handler is interested in. Improved method invocation to not unnecessarily wrap exceptions thrown from them. Changed the test cases to throw a dedicated runtime exception to implicitly test that the 

Renamed LinkSaveEvent to LinkedEntityEvent as it's not only used for save-events for entities. Make use of Methods' USER_METHOD filter. Moved the class into the util package. Removed the UUID converter as Spring's DefaultFormattingConversionService provides it out of the box.

Added missing license headers and JavaDoc. Deprecated Class<?> attributes on handling annotations.

Related pull request: #151.
This commit is contained in:
Oliver Gierke
2014-12-04 18:56:29 +01:00
parent e6a19a366d
commit 7f990b006b
27 changed files with 675 additions and 351 deletions

View File

@@ -1,20 +1,20 @@
[[events-chapter]]
= Events
There are eight different events that the REST exporter emits throughout the process of working with an entity. Those are:
There are eight different events that the REST exporter emits throughout the process of working with an entity. Those are:
* BeforeCreateEvent
* AfterCreateEvent
* BeforeSaveEvent
* AfterSaveEvent
* BeforeLinkSaveEvent
* AfterLinkSaveEvent
* BeforeDeleteEvent
* AfterDeleteEvent
* `BeforeCreateEvent`
* `AfterCreateEvent`
* `BeforeSaveEvent`
* `AfterSaveEvent`
* `BeforeLinkSaveEvent`
* `AfterLinkSaveEvent`
* `BeforeDeleteEvent`
* `AfterDeleteEvent`
== Writing an ApplicationListener
There is an abstract class you can subclass which listens for these kinds of events and calls the appropriate method based on the event type. You just override the methods for the events you're interested in.
There is an abstract class you can subclass which listens for these kinds of events and calls the appropriate method based on the event type. You just override the methods for the events you're interested in.
[source,java]
----
@@ -30,56 +30,44 @@ public class BeforeSaveEventListener extends AbstractRepositoryEventListener {
}
----
One thing to note with this approach, however, is that it makes no distinction based on the type of the entity. You'll have to inspect that yourself.
One thing to note with this approach, however, is that it makes no distinction based on the type of the entity. You'll have to inspect that yourself.
== Writing an annotated handler
Another approach is to use an annotated handler, which does filter events based on domain type.
To declare a handler, create a POJO and put the `@RepositoryEventHandler` annotation on it. This tells the `BeanPostProcessor` that this class needs to be inspected for handler methods.
To declare a handler, create a POJO and put the `@RepositoryEventHandler` annotation on it. This tells the `BeanPostProcessor` that this class needs to be inspected for handler methods.
Once it finds a bean with this annotation, it iterates over the exposed methods and looks for annotations that correspond to the event you're interested in. For example, to handle BeforeSaveEvents in an annotated POJO for different kinds of domain types, you'd define your class like this:
Once it finds a bean with this annotation, it iterates over the exposed methods and looks for annotations that correspond to the event you're interested in. For example, to handle `BeforeSaveEvent`s in an annotated POJO for different kinds of domain types, you'd define your class like this:
[source,java]
----
@RepositoryEventHandler
public class PersonEventHandler {
@HandleBeforeSave(Person.class) public void handlePersonSave(Person p) {
... you can now deal with Person in a type-safe way
@HandleBeforeSave
public void handlePersonSave(Person p) {
// … you can now deal with Person in a type-safe way
}
@HandleBeforeSave(Profile.class) public void handleProfileSave(Profile p) {
... you can now deal with Profile in a type-safe way
@HandleBeforeSave
public void handleProfileSave(Profile p) {
// … you can now deal with Profile in a type-safe way
}
}
----
You can also declare the domain type at the class level:
The domain type whose events you're interested in is determined from the type of the first parameter of the annotated methods.
[source,java]
----
@RepositoryEventHandler(Person.class)
public class PersonEventHandler {
@HandleBeforeSave public void handleBeforeSave(Person p) {
...
}
@HandleAfterDelete public void handleAfterDelete(Person p) {
...
}
}
----
Just declare an instance of your annotated bean in your `ApplicationContext` and the `BeanPostProcessor` that is by default created in `RepositoryRestMvcConfiguration` will inspect the bean for handlers and wire them to the correct events.
Just declare an instance of your annotated bean in your `ApplicationContext` and the `BeanPostProcessor` that is by default created in `RepositoryRestMvcConfiguration` will inspect the bean for handlers and wire them to the correct events.
[source,java]
----
@Configuration
public class RepositoryConfiguration {
@Bean PersonEventHandler personEventHandler() {
@Bean
PersonEventHandler personEventHandler() {
return new PersonEventHandler();
}
}