Hi!
As far as I understand, Axon handles commands / events by their fqdn names.
Wondering is there any way to make Axon handle child command / event by specifying its parent class? E.g:
class ParentCommand {
// ...
@TargetAggregateIdentifier
String aggregateId;
}
class ChildCommand extends ParentCommand {
}
@CommandHandler
public void handle(ParentCommand command) {
// ...
}
In the example above, I would like the handler to be invoked whenever ParentCommand or ChildCommand received (currently it works only for ParentCommand)
Maybe you can create an interface and have both commands implement it. Then handle the interface in you command handler.
I've never tried this exactly, but it seems like it should work.
Hi Vladyslav and Troy,
Axon requires a specific handler for every command.
If you’d publish a ChildCommand in your example, the ParentCommand Command Handler will not receive the command.
Instead you’ll be prompted with a ‘NoHandlerForCommandException’.
The idea with commands is that they’re pointing to one single (target aggregate) instance.
For events your assumption is correct though.
An @EventHandler
annotated function listening to a ChildEvent
for example will also listen to a ParentEvent
(if ChildEvent extends ParentEvent
that is).
Axon will search for the most specific event handling function in an Event Handling Component to handle a given event.
That thus means that if an Event Handling Component has Event Handlers for both the ChildEvent and ParentEvent, and a ParentEvent is being handled at that point, that only the ParentEvent Event Handler will receive the event.
I hope this gives you some background on the situation.
By the way Vladyslav, were you asking this out of curiosity or do you have a use case where this would be easy/necessary?
Cheers,
Steven
Hi Steven,
Thanks for clarification, you even answered some of my not-yet-asked questions about event handling.
So, as far as I understood, for case when we have ParentEvent and ChildEvent and 2 handlers - one of which accepts ChildEvent and other - ParentEvent, the logic would be as follows:
-
if ChildEventReceived - only handler, which accepts ChildEvent invoked, but not the one accepting ParentEvent
-
if ParentEventReceived - a handler, which accepts ParentEvent invoked
For commands handling, we have some authorization logic, which is checked in DispatchInterceptor. Basically, it is just a @HasPermission(“somePermission”) annotation on command class which is checked against HTTP header.
We have multiple commands, like SaveCertificateCommand with ‘Save’ permission and SaveApprovedCertificateCommand with ‘Save’ and ‘Approve’ permissions, which extends from SaveCertificateCommand and we wanted to have a handler only for SaveCertificateCommand, which handles SaveCertificateComand and also SaveApprovedCertificateCommand
Hi Vladyslav,
No problem, I am glad to have been of help.
Your assumption around the event handlers is correct. The shortest explanation I could give you on this is that ‘axon will look for the most specific event handler for a given event’.
Thus if you have an Event Handling Class with both the Parent and Child events being handled in it, a ParentEvent will always be handled by the ParentEvent Handler and vice versa.
But if you have an Event Handling Class with only a ChildEvent handler in it, that handler will both handle the Parent and Child event, is the ChildEvent handler is 'the most specific handler for that given event based on class hierarchy.
Your use case with the command handling doesn’t sound to weird.
Sadly though, like I pointed out, this message hierarchy does not work for command messages, only for event messages.
I’d thus suggest to have a dedicated command handler for your SaveApprovedCertificateCommand.
Much luck and fun furthering your experience with the framework, and please keep us apprised of any questions you might have!
Cheers,
Steven
Thanks, Steven.
Actually, event handling logic works as we expected, and the logic itself is very powerful and handy.
As for commands, we did solve our case as you described and it is currently just a command handler which calls another one.
Thanks again for taking your time!