ClassCastException when using JCache

Hello,

I am using Axon 2 Milestone 1.

I am getting a ClassCastException when trying to load a aggregate in a command handler.

Here my workflow:

I have two different AggregateRoots and one Saga.
The two aggregate roots (different types of accounts) have the same aggregateIdentifier value (both accountId).

  1. AggregateRoot A is applying an event.
  2. Saga is handling the event and dispatching a command
  3. CommandHandler of AggregateRoot B is handling the command, but when I try to load AggregateRoot B I get a ClassCastException:
    AggregateRootB aggregate = repository.load(command.getAccountId(); // repository == Repository

Without JCache it works fine.

Here the error:

2012-07-16 19:15:25,162 [http-8080-1] INFO org.axonframework.commandhandling.interceptors.LoggingInterceptor - Incoming command: [ReceiveAppleCommand]

2012-07-16 19:15:25,162 [http-8080-1] DEBUG org.axonframework.unitofwork.UnitOfWorkListenerCollection - Registering listener: org.axonframework.eventsourcing.CachingEventSourcingRepository$CacheClearingUnitOfWorkListener

2012-07-16 19:15:25,162 [http-8080-1] DEBUG org.axonframework.unitofwork.UnitOfWorkListenerCollection - Registering listener: org.axonframework.repository.LockingRepository$LockCleaningListener

2012-07-16 19:15:25,162 [http-8080-1] WARN org.axonframework.commandhandling.interceptors.LoggingInterceptor - [ReceiveAppleCommand] execution failed:

java.lang.ClassCastException: com.myproject.domain.AggregateRootA cannot be cast to com.myproject.domain.AggregateRootB

at com.myproject.commandhandler.AggregateRootBCommandHandler.handle(AggregateRootBCommandHandler.java:38)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

at java.lang.reflect.Method.invoke(Method.java:597)

at org.axonframework.common.annotation.MethodMessageHandler.invoke(MethodMessageHandler.java:105)

at org.axonframework.common.annotation.MessageHandlerInvoker.invokeHandlerMethod(MessageHandlerInvoker.java:79)

at org.axonframework.commandhandling.annotation.AnnotationCommandHandlerAdapter.handle(AnnotationCommandHandlerAdapter.java:92)

at org.axonframework.commandhandling.DefaultInterceptorChain.proceed(DefaultInterceptorChain.java:62)

at org.axonframework.commandhandling.DefaultInterceptorChain.proceed(DefaultInterceptorChain.java:68)

Thanks for your help

Hannes

Hi Hannes,

the repositories store the aggregates in the cache under their identifier. You should not use the same cache instance to store two different types of aggregates. Configuring two different caches (in EhCache it’s just a matter of selecting a different name) should solve your problem.

Cheers,

Allard

Thanks for your help.

Do you have an example how I can declare it?

I am using it the way you did it in your example:

<axon:event-sourcing-repository

id=“creditInRepository”

aggregate-type=“com.myproject.domain.AggregateRootA”

cache-ref=“ehcache”

event-bus=“eventBus”

event-store=“eventStore”>

</axon:event-sourcing-repository>

Thanks!

Hannes

Hi Hannes,

The EhCacheFactoryBean has a property “cacheName”, which allows you to define the cache you want to use. The cacheName creates a cache using the configuration specificied under that name in ehcache.xml. If no explicit configuration is found, it uses the default configuration.

Example (where we have an aggregate “game”):

The ehcache.xml:

Games, in this application, are relatively short lived. That’s why we have configured a timeToLive. For other applications, you might require a longer one, or maybe even eternal. Generally, you don’t want to overflow to disk, as the overhead of disk storage might not weigh up to the benefit it gives you.

Cheers,

Allard