Handling an Aggregate Not Found Exception

Hi there,

I am using the Axon release (1.3) and I am having some bother when
calling the load(AggregateIdentifier) method on my implementation of a
GenericJpaRepository.

When I attempt to load a StringAggregateIdentifier that does not exist
- I would expect to be able to catch an AggregateNotFoundException so
that I can take measures in the code to create the Aggregate before
applying the intended command to it.

It seems that my implementation is in fact throwing a
NullPointerException which I am not able to catch before it causes
mayhem with transaction rollbacks...

INFO [org.axonframework.repository.LockingRepository] Exception
occurred while trying to load an aggregate. Releasing lock.
java.lang.NullPointerException
  at
org.axonframework.unitofwork.DefaultUnitOfWork.registerAggregate(DefaultUnitOfWork.java:
94)
  at
org.axonframework.repository.AbstractRepository.load(AbstractRepository.java:
71)
  at
org.axonframework.repository.LockingRepository.load(LockingRepository.java:
119)
  at
org.axonframework.repository.AbstractRepository.load(AbstractRepository.java:
79)
  at
com.atlaschase.falcon.commands.domain.repositories.aircraft.AircraftService.getAircraftFromHexcode(AircraftService.java:
20)

The question I would like to ask is how can I handle situations when
the aggregate returned from the entity manager is null? In the sample
application - there is a seperate repository of contactNames that
checks for uniqueness but there is no obvious handling of how
AggregateNotFoundException... is this still thrown?

Thanks for your time

Simon

Hi Simon,

I am afraid this is a bug in the GenericJpaRepository implementation. I will fix this shortly.

In the meantime, as a workaround, you can subclass the GenericJpaRepository, override the “doLoad(AggregateIdentifier, Long)” method.
This implementation of the overridden method should do the job for you:

@Override
protected T doLoad(AggregateIdentifier aggregateIdentifier, Long expectedVersion) {
T aggregate = super.doLoad(aggregateIdentifier, expectedVersion);
if (aggregate == null) {
throw new AggregateNotFoundException(aggregateIdentifier, format(
“Aggregate [%s] with identifier [%s] not found”,
aggregateType.getSimpleName(),
aggregateIdentifier.asString()));
}
return aggregate;
}

Sorry for the inconvenience.

Cheers,

Allard Buijze

Okay - well that makes me feel a little better - I thought I was just
going mad!

Thanks for the work around. Will this fix be in the next release?

Also - another question on Unit of Work and Transactions....

I currently wrap any calls to the repository in a transaction such
that the bounds of the transaction are limited to the add and load
invocations on the database. This is a problem for the the framework
it would seem - since I keep receiving a 'no transaction is in
progress' error and subsequently I am not able to persist any changes
to the aggregate.

It seems like the boundaries of the transaction need to extend to the
command dispatch - is this right? My integration tests are successful
when I wrap the dispatch process in a transaction. For me, this is a
little confusing since the documentation says

"If this is important to your application (although it should be
avoided as much as possible), consider using a Transaction Interceptor
on the command bus that attaches a transaction to the Unit of Work." -
this would imply that a transaction that wraps the UoW is not
essential - and should be used sparingly...

Have things changed then? Must I wrap all my command handling in a
Transaction?

Thanks Allard...

oh by the way - when is the next training seminar in Amsterdam? I need
to book to that!!

Simon

Hi Simon,

thanks for the feedback on this. I have just applied a fix to all of the maintenance branches. There is one other thing I am working on. Once that is complete, I will create a new release. It is likely to be finished at the end of this week, or otherwise early next week.

The actual persistence of the changes is not done in the scope of the Command Handler. It is done just after the Command Handler invocation is completed. The only thing you can do is configure a TransactionInterceptor (there is a SpringCommandHandlerInterceptor if you use Spring).

I apologize for the misleading nature of that sentence. I have removed it for future versions. There is nothing wrong with using the TransactionalInterceptor, but if it’s possible to do without transactions, that always the better option. This interceptor makes sure you have a transaction around the Command Handler invocation, aggregate persistence and event publication processes. This means that, if you use the SimpleEventBus, you can also update your Query Models in the same transaction. For many applications, that’s very useful.

About the training, are you referring to the 2-day immersion course, or the 1-day workshop? We’ll be planning both of them shorty. I will keep you updated.

Hope this helps.

Cheers,

Allard

Hi Allard,

I am indeed using Spring and this seems to have solved the issue - thanks again,

I would like information on both events (1 and 2 day). I will book the 1 day first and then - if more assistance required - I will go for the full 2 day.

Thanks again for your prompt and helpful replies.

Simon

Hi there,

AggregateNotFoundException.txt (12.1 KB)

Hi,

I am not sure what you expect me to do, but the exception seems to be thrown by your own class. Perhaps there is something wrong with the query, so that it yields no response?

Cheers,

Allard