Security and Serialization in Axon

Hi,

with that remark, I was referring to the following lines:

Task task = event.getTask();
task.setState(TaskState.CREATED);

Apparently, the Task class contains mutable state. Objects with mutable state should never be part of your events, as they effectively make your event mutable. Just imagine multiple handlers concurrently handling an event whose state is changing. The outcome is then completely non-deterministic.

Cheers,

Allard

So if I have something like

`
@CommandHandler
public TaskAggregate(CreateTaskCommand command) throws Exception {
Task task = new Task();
task.creationDate = DateTime.now();
apply(new TaskCreatedEvent(task) );
apply(new TaskStartedEvent(task) );
}

@EventSourcingHandler
public void on(TaskCreatedEvent event) throws Exception {
this.id = event.getId();
Task task = event.getTask();
task.setState(TaskState.CREATED);
}

@EventSourcingHandler

public void on(TaskStartedEvent event) throws Exception {
Task task = event.getTask();
task.setState(TaskState.STARTED);
}
`

I may not have the Task set as STARTED after UOW commits? And BTW, is it OK to have more than one Event raised by one Command?

Also a important question is that one of the CommandHandlerInterceptor accessing the aggregate itself. Is there a way to get the Aggregate using the UnitOfWork in the CommandHandlerInterceptor?

Thanks.

HI,

it’s not so much about the unit of work. When you have an entity as part of your events, you don’t have control over what component will change it’s state. Event Handler (outside of the aggregate) may be handling an event asynchronously, causing annoying race conditions.
So instead of including the Task in your event, describe the task. The Task class is an implementation detail only relevant to the command model. Including the Task object in your event will cause that model to be “suitable” for both mutation and queries, basically removing the whole idea of CQRS. Besides the danger of shared mutable objects…

Raising multiple events from a single command is a very common thing. In the end, events must have functional meaning. A single command can have multiple effects.

Cheers,

Allard

OK, I understand now, I’m assuming the Task will be in a state that can actually be modified by a external listener, which rends the “state keeping” function of the Aggregate moot.

What about the question about the CommandHandlerInterceptor accessing the aggregate?. Is there a way to get the Aggregate using the UnitOfWork in the CommandHandlerInterceptor?

Sorry to insist but I’m working on it right now and a lot of code (actually including some design decisions) are depending on being able or not to do it.

Cheers.

Hi Antonio,

at this moment, the command handler interceptor cannot access the aggregate. If you need to validate anything that requires aggregate state, you must do so within the aggregate itself.

Cheers,

Allard

Hi again…

In relation to what I said earlier

Serialization:
We have to support Postgres with XML data types. That means serialize Metadata, Events and Sagas to XML (or a string representation of) and store then as XML. For that I had to implement a Axon Serializer, extend GenericEventSqlSchema, PostgresSagaSqlSchema and JdbcSagaRepository. Not a big problem here but the code could be more clean with some small changes in Axon itself, if you want to discuss that I’ll be happy to do it.

we are having a big concern. At the moment my AxonPostgresqlSerializer is using:


public <T> SerializedObject<T> serialize(Object object, Class<T> expectedRepresentation) {

if (object instanceof MetaData || object instanceof Saga) {
 // use XStream
} else {
 // use JAXB
}

That is because we have control over our own commands/events (the payloads of Message) that are currently annotated with JAXB that guarantees the object will always be dessiralizable . However, we have no control over Metadata and Saga and thus we use the XStream introspection mechanism. But that means if something changes in the Saga implementation, introspection will fail in the future.

Is there any mechanism in place to take care of this? Like a Saga Upcasting or something?

Cheers.

Hi,

the SagaRepository doesn’t use upcasters, by default. However, in a similar situation, I have once implemented a wrapper for a Serializer that invokes some upcasters before invoking the wrapped serializer. It’s fairly simple to implement and does the job.

Cheers,

Allard