How to create an instance of an aggregate from an external command handler - Exception : Cannot request current Scope if none is active -

Hi,
Im using axon-spring-boot-starter version 4.0

I don’t have any trouble when having a @CommandHandler annotation on the aggregate’s constructor.
However, when I try to use an external command handler for an aggregate rather than using @CommandHandler annotation on the constructor. I get this error.

Not sure how to create a new instance of an aggregate from an external command handler.

Also, Please suggest if it’s not the best practice to create an instance of an aggregate from an external command handler.

`
@Service
class PaymentCommandHandler() {

@CommandHandler
fun onCreatePaymentCommand(command: CreatePaymentCommand): UUID {
PaymentAggregate(command)
return command.id
}
}

@Aggregate
class PaymentAggregate() {
@AggregateIdentifier
@Id

constructor(command: CreatePaymentCommand) : this() {
AggregateLifecycle.apply(PaymentCreatedEvent(command.id))
}

@EventSourcingHandler
fun onPaymentCreatedEvent(event: PaymentCreatedEvent){

}

}
`

I’d like to see the answer to this. As far as I know Axon doesn’t simply provide the aggregate anywhere. If you need to access the aggregate you will need to use the Repository’s load function (https://axoniq.io/apidocs/4.0/org/axonframework/modelling/command/Repository.html) . And even so, you only you have access to the Aggregate wrapper.

I would love to be able to have easier access to an aggregate (on the command side) , for example to test the actual existence …

Hopefully Allard can tell you more.

Hi Mani, David,

If you’d want to create/load an aggregate from an External Command Handler, you’re as David suggest indeed required to use the aggregate Repository.
For creating a new aggregate, you can leverage the newInstance(Callable<T>) function, whilst for loading an aggregate you can use the load(String)/load(String, Long) functions on the Repository implementation.

This will, as David also points out, return you the ‘wrapper’ around your Aggregate.
To from here on call a function on your Aggregate implementation whilst correctly setting the Scope of that Aggregate instance as the current Scope, you’re required to use execute(Consumer<T>) function (which is part of the Aggregate<T> which is returned by the Repository).

Now, in regards to your ‘best-practice’ request Mani.
We’d typically suggest to have the @CommandHandler annotated functions on your domain model directly.
Thus, put them on the Aggregate class.
This will eliminate the need to deal with the aggregate Repository (as I’ve described above) entirely.

You are however free to still use the Repository for other needs (which might answer your question David).

This will likely depend on your use case.

So, if this does not answer your question sufficiently Mani, please provide an explanation why you’re looking to instantiate an Aggregate from an External Command Handler.

I hope this helps you out guys!

Cheers,
Steven

PS. David, I hope it’s okay that I am answering the question instead of Allard. :wink:

The answer is much appreciated! X-D

Thanks @Steven and @David

Having the below config, I would expect axon autoconfiguration to create this repository bean and wire it for me. However, doesn’t look it does. Am I missing something else here?
FYI if it helps - I’m using axon server and looking for EventSourcingRepository to be injected for the aggregate.
I have an axon server locally running in my machine.
I haven’t acutally made any extra spring boot config for axon. Just rely on axon Spring boot autoconfiguration to make sensible defaults.

`
@Service
class PaymentCommandHandler(private val paymentAggregateRepository: Repository) {

@CommandHandler
fun onCreatePaymentCommand(command: CreatePaymentCommand): UUID {
paymentAggregateRepository.newInstance{
PaymentAggregate(command)
}
return command.id
}
}
`

Hi Mani,

If you’re using the axon-spring-boot-starter dependency, I would expect that any Aggregate implementations you’d have would automatically get an Aggregate Repository initialized too.
Important in this though is to use the @Aggregate stereo type annotation on your Aggregate (contained in the axon-spring module).

Without that annotation, Axon will not know that your aggregate implementation is an Aggregate it should look for to initialize all the necessary infrastructure for you.
Is my guess right that that’s the missing link in your scenario?

If not, let’s investigate further.

Cheers,
Steven

I have @Aggregate on my aggregate. I get failure only if I use external command handler. It’s fine otherwise. Not sure what’s the missing bit here.

Hi Mani,

Alright, good to know.
Could you be a bit more specific on ‘what’ failure you get when using an External Command Handler?

From this thread I feel I’ve heard several potential things going wrong, not sure what way to look for at the moment.

Is it actually configuring your External Command Handler which fails?
Or is it calling the Repository to create a new instance which fails?

Maybe a stack trace would be valuable here to point out what’s missing?

Cheers,
Steven

Silly question, but have you started a UnitOfWork?

To query the repository, it needs to be done inside a unit of work …

I believe this could be due to an ordering issue in the creation of beans.

Just to reclarify the scenario and make sure we are all talking about the same thing:

  1. We have a command handler, that is injected with an aggregate repository (in my case event sourced)
    This is annotated with an @Service spring annotation, and is using constructor injection to get the repository (so we can call newInstance)

  2. We have an event sourced aggregate annotated with @Aggregate, with the constructor not annotated with the @CommandHandler annotation.

When i boot the application with this configuration, i get a null pointer exception which causes the the application to terminate.

Error snipper:
Caused by: java.lang.NullPointerException: null
at org.axonframework.config.AggregateConfigurer.lambda$new$11(AggregateConfigurer.java:91) ~[axon-configuration-4.0.3.jar:4.0.3]

Code snippet where error occurs in AggregateConfigurer:
87 repository = new Component<>(
88 () -> parent,
89 “Repository<” + aggregate.getSimpleName() + “>”,
90 c -> {
91 state(c.eventBus() instanceof EventStore,
92 () -> "Default configuration requires the use of event sourcing. Either configure an Event " +
93 "Store to use, or configure a specific repository implementation for " +
94 aggregate.toString());

The error occurs on line 91 at the c.eventBus() call. This is because c (the component builder function is null)

The change i made to get this working was to add a @DependsOn(“eventStore”) annotation on my CommandHandler. This changes the order of bean creation such that it now boots successfully.

Hi Mani, David, Andrew,

That’s an…interesting issue you’ve found there Andrew.
I’ve just been verifying the configuration process and I can imagine such a situation might occur.

Sad to hear the Spring wiring is causing the issue.

I can share with you all that we’re planning to adjust the wiring process somewhat, to a more robust format.
I’ll ensure that we’ll check this case as well, so that future release will not contain this problem.

Thanks for sharing this Andrew!
Mani, would you mind trying out the suggested approach above to see if it resolves your problem?

Cheers,
Steven

Thanks Steven, Andrew and David.
It did fix it now.

Thanks