Automatic Persistence of Command State [Axon Framework]

Viewed 2102

I'm looking into the Axon framework and I'm having a hard time with the automatic persistence of the command state.

I've looked at the documentation regarding the command model repository and from my understanding the state of the command model for the standard repository should be auto-persisted provided I have the correct dependencies. This sentiment is also present in another blog/tutorial I've looked at (you might need to scroll down a bit to the Repository section).

The problem is that although I've added the axon-mongo dependency, the command state is not being persisted automatically. I've tried to configure the relevant Repository beans as per the docs but It doesn't seem to have worked either. I'm not even sure whether this is required given that (from my understanding of the docs) you would do this mainly if you want to query the command state.

While I understand that I can create my own repository and save the entities myself (similar to this tutorial), I'd rather not given seems to provide this out of the box.

Am I missing something here?

NOTE: My Mongo setup seems to be correct since I've managed to persist my events in MongoDB as per the documentation.

UPDATE

As per Steven's comment (and subsequent comments), I decided to try and implement a state-stored aggregate however I found an issue with the (de)serialization of the aggregate. I've sent my Aggregate to Steven and he has confirmed that it is simple enough that it should be (de)serialized by XStream. I have also tried to serialize my aggregate using a standalone instance of XStream and it worked, which led me to believe that this is more of an Axon issue than an XStream issue. I also tried to use the Jackson and java (de)serializers (since they are the other options provided by Axon) and I found similar problems. I have concluded that this is an Axon bug and i have stopped trying to solve the issue.

1 Answers

From your question it is not immediately clear if you are aware of the possible Command Model storage mechanisms you can choose from. So firstly, like @Mzzl points out in his comment, you can view the Command Model state from two angles:

  1. Event Sourced
  2. State-stored

By default, Axon Framework will set up your Aggregate with an EventSourcingRepository behind it. This means, that if an Aggregate (e.g. your Command Model) is required to handle a new Command, that the Aggregate will be loaded by retrieving a stream of all the events that it is has published. Second, it will call all the @EventSourcingHandler annotated methods on your Aggregate implementation to recreate the state of the Command Model. Lastly, once all the Events which are part of the Aggregate's Event Stream have been handled, the command will be provided to the @CommandHandler annotated method.

The state-stored approach is obviously a little different, as this means the entirety of your Aggregate will be stored in a repository.

Note though, that the State-Stored approach is only supported through the GenericJpaRepository class. Thus, storing the Aggregate in it's entirety in a MongoDB is not an option. If you are looking for an Event Sourcing approach for your Aggregate, the events can be sourced from any EventStore implementation covered by the framework. That thus means you can choose JPA, JDBC, MongoDb and Axon Server as the means to storing your events and retrieving a stream of events to recreate your Command Model.

Configuration wise, there are a couple of approaches to this. If you are using the Configuration API provided by Axon directly, you can use:

  1. AggregateConfigurer#defaultConfiguration(Class<A>) for an Event Sourced approach
  2. AggregateConfigurer#jpaMappedConfiguration(Class<A>) for a State-Stored approach

If you are in a Spring Boot environment with your application, it's a little simpler to switch between event sourced and state-stored. Simply having the @Entity annotation on your Aggregate implementation is sufficient for the framework to note you want to store the Aggregate as is.

Hope this sheds some light on the situation @The__Malteser!


Update

Based on the comments, it's clear that the XStreamSerializer which the framework uses by default to de-/serialize objects, is incapable of serializing your Aggregate instance in a State-Stored fashion.

Based on the exception you're receiving, being Cannot marshal the XStream instance in action, I did some searching/digging. I have a hunch that XStream is by default not capable to simply serialized non-static inner classes.

However, as we're not sure what the implementation is of your Aggregate, it's hard to deduce whether that's the problem at hand. Would you be able to share your implementation with us here so that we can better deduce whether an inner class is the problem?

Related