Unable to inject Aggregate EventSourcing Repository bean into annotated com

`
@Aggreagate
class MyFirstAggregate constructor() {

@AggregateIdentifier
private lateinit var id: Id

@CommandHandler
constructor(cmd: CreateMyFirstAggregateCommand) {
}
}

@Aggregate
class MySecondAggregate constructor(){

@AggregateIdentifier
private lateinit var id: Id

@CommandHandler
constructor(cmd: CreateMySecondAggregateCommand, myFirstAggregateRepository: Repository){
try {
myFirstAggregateRepository.load(cmd.mySecondAggregateId)
// do create the second aggregate
AggregateLifeCycle.apply(MySecondAggregateCreatedEvent(cmd.mySecondAggregateId))
} catch(e: AggregateNotFoundException) {
// reject the command
}
}
}
`

Axon Version: 4.2.1
Assume I’m using all default configurations from axon-spring-boot-starter.

Given this scenario I am unable to init the application because axon fails to inject myFirstAggregateRepository into the second aggregate command handler.

Maybe using @AutoWired as an instance variable would work?

To be honest I’ve never considered doing that, loading aggregates from other aggregates feels...impure. However the framework has cross-aggregate createNew functionality, so reading isn’t so far fetched. I’ll have to give this a try!

According to documentation the second expected parameter of a CommandHandler should be a UnitOfWork (see package org.axonframework.messaging.unitofwork for candidate implementations).

Looks like you got a piece of documentation from EventHandler which yes can autowire a Component if it is available in the Spring Context.

In your case following the @Joel’s advise and autowire the Repository in your aggregate seems to be the way to go.

regards,

-Rogério

I tried to get this working in command and event handlers w/ autowiring and parameter injecting. Nothing worked. Can’t say I’m surprised as this probably violates some tenant of DDD.

Yeap, maybe some trick is necessary here.

I used to load events in the command side defining the Repository as a spring bean on AxonConfig class:

@Bean
public Repository repositoryForMyAggregate(EventStore eventStore) {
return EventSourcingRepository.builder(MyAggregate.class).eventStore(eventStore).build();
}

Maybe this is the only or safe way to have it.

regards,

-Rogério

Hi all,

please note that parameter injection for Axon isn’t a full-fledged dependency injection mechanism. The Spring-bean injection will only work when there is a single bean of the expected type available. Because of generics type erasure, the type of the repository parameter is Repository. There are most likely multiple Spring beans that implement that interface (one for each aggregate).

But in this case, I’d argue that directly calling an aggregate from another is a design smell. Aggregates should execute their logic independent of eachother. Wherever they have a dependency, this is implemented using a Saga, Process Manager or “just-an-eventhandler-sending-commands”.
I can’t really make up your use case from the example, but it seems you want to create an aggregate from another. That’s a common use case, and is supported by Axon’s API directly. On the aggregate that already exists, call AggregateLifecycle.createNew(MySecondAggregate.class, () -> new MySecondAggregate(constructor, params));

Hope this helps.
Cheers,

Allard Buijze

CTO