actually had to think a while about this one. It’s something that we wanted to implement in Axon generically at some point (that’s why Axon 4 has an explicit CommandResultMessage, allowing us to add additional information in the future).
I think the least intrusive way to implement this, would be using a HandlerEnhancerDefinition. This allows you to alter the behavior of any message handler (Command, Query and Event) in Axon. In your case, you would want to wrap Command handlers with an instance that changes the return value of a handler.
You should be able to use AggregateLifecycle methods from within the definitions.
You will need to register your HandlerEnhancerDefinition using the ServiceLoader mechanism. In a file called “META-INF/services/org.axonframework.messaging.annotation.HandlerEnhancerDefinition” add a line with the fully qualified class name of your implementing class. Axon will then automatically pick it up.
the HandlerEnhancer is not documented at the same level as other components, because we don’t really consider it part of the standard API. It’s a pretty low-level feature that you can use to tweak things.
The method you’d want to override in this case, is the handle(Message, T) method. T is the actual target instance on which the method will be executed. This is either your aggregate root, or an entity within that aggregate. In either case, you should be able to do AggregateLifecycle.version() and AggregateLifecycle.identifier() to get the version and identifier, which you will want to use to construct your return value.
I am implementing this requirement in the way describe above but I have an issue during the first command that constructs the aggregate. The target instance of the handle method is null which prevents me from the getting the version of the aggregate.
What did you do to get the version upon creation of the aggregate?
the constructor is indeed a special case. Instead of passing the aggregate instance as a parameter, it returns the instance as a result. Unfortunately, changing the return value of those methods will be problematic, as the repository expects the created aggregate to be returned from a constructor.
Instead, the AggregateAnnotationCommandHandler is the class that manages the invocations of command handlers defined in Aggregate instances. It has a protected method “resolveReturnValue”, which allows you to customize the return value of constructor command handlers. The reason being that we do not expect anyone to want to return the aggregate instance that was created.
You can use the AggregateConfigurer to configure a custom AggregateAnnotationCommandHandler instance, which overrides this method. We haven’t provided a separate configuration hook for this, just yet.
Yes I already got it working with a custom AggregateAnnotationCommandHandler.
A “clean” hook for this or a way to always have the new aggregate version returned would still be nice though. But I understood it is somewhere in the backlog.