address book sample command handler domain exception not being thrown

Here is the scenario…unit tests of address book sample work and pass thwroing the ContactnameAlreadyTaken Exception. the challenge is that with transaction management and JPA when dispatching command on command bus cannot get back the BusinessDomain exception handling but instead gets the JPA exception, even though the command handler throws the business exception as in the address-book sample code. Snippet of trace showing JPA Exception instead of desired ContactNameAlreadyTakenException with the CommandCallBack on failure throwable cause parameter…Any ideas or suggestions on what could be going wrong… Below is snippet of stack trace illustrating the issue.

2011-05-17 23:47:26,345 [SimpleAsyncTaskExecutor-2] WARN com.addressbook.server.domain.contact.commandhandler.JpaContactNameRepository - Unable to claim contact Name. Contact with name already exists

2011-05-17 23:47:26,346 [SimpleAsyncTaskExecutor-2] ERROR com. addressbook.server.seviceCallingCommandViaCommandBus - Contact seems to be existing with cause - org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly

org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly

at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:476)

at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)

at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)

at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393)

at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:120)

at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)

at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)

at $Proxy38.claimContactName(Unknown Source)

at com.addressbook.server.domain.contact.commandhandler.ContactCommandHandler.handle(ContactCommandHandler.java:50)

Hi,

we’ll look into it, although the sample app doesn’t have the highest priority at the moment.
Thanks for reporting!

Cheers,

Allard

Thanks,

Sample is just for illustration of the broader issue. The challenge is that domain exceptions need to be caught by whatever calls the command bus is key for generation of business constraint violations in apps.

One workaround which has made it work for me is that the JPA entity have the annotation of @Transactional(propagation = Propagation.REQUIRED) vs @Transactional(propagation = Propagation.REQUIRES_NEW). This is on the JPAContactNameRepository class. This may have to do with how SimpleCommandBus handles exceptions and propagates them to its callers and a best practice around JPA transaction management. The key challenge is that strongly typed business exceptions are key for generation of domain constraint violations to callers (business domain state based validation exceptions, e.g. like the name already exists).

Cheers…

Hi,
I had a good look at the sample and to be honest I do not really understand the problem. The command handler throws the the business exception ContactNameAlreadyTakenException. This exception is noticed by the command bus, but by default nothing really happens with it. This changes the moment you provide a future callback to the command dispatching. Using the future callback, you are notified using an ExecutionException. The cause of the exception is a ContactNameAlreadyTakenException. So within the spring mvc controller I have now access to the ContactNameAlreadyTakenException.

I committed the change in the class org.axonframework.examples.addressbook.web.ContactsController in the trunk. Could you please verify if this is what you mean? If not I’ll be happy to have a better look at your problem.

regards Jettro