Axon Upcasting, do I have to create an upcaster for each revision?

I have looked through the code in the example of document and I wonder. So I’m concerning that, do I have to create an upcaster for each revision. Suppose, I have like 10 revisions for a single event. Do I need to create 10 classes for upcasting from revision 1 to 10. And also if I have a lot of events in my application that need to be changed, do I need to create an upcaster for each of them.

Hi,

I am not an Axon developer, but I will still try and answer your question.

You can write an upcaster which handles multiple events and multiple revisions. This can be done by implementing EventUpcaster instead of extending SingleEventUpcaster. The following example upcaster is able to handle four different types of events (MyEvent1 to MyEvent4) and upcasts them from Revision 1 directly to Revision 5. The upcaster assumes that the payload can be transformed into a JsonNode.

@Component
@Order( 1 )
final class MyUpcaster implements EventUpcaster {

	private final List<String> relevanteEvents = Arrays.asList(
			MyEvent1.class.getCanonicalName( ),
			MyEvent2.class.getCanonicalName( ),
			MyEvent3.class.getCanonicalName( ),
			MyEvent4.class.getCanonicalName( ) );

	@Override
	public Stream<IntermediateEventRepresentation> upcast( final Stream<IntermediateEventRepresentation> intermediateRepresentations ) {
		return intermediateRepresentations.map( this::potentialUpcast );
	}

	private IntermediateEventRepresentation potentialUpcast( final IntermediateEventRepresentation intermediateRepresentation ) {
		final SerializedType serializedType = intermediateRepresentation.getType( );
		if ( serializedType.getRevision( ).equals( "1" ) && relevantEvents.contains( serializedType.getName( ) ) ) {
			return intermediateRepresentation.upcastPayload( new SimpleSerializedType( serializedType.getName( ), "5" ), JsonNode.class, this::upcast );
		} else {
			return intermediateRepresentation;
		}
	}

	private JsonNode upcast( final JsonNode data ) {
		...
	}

}

Best regards,

Nils

Hi,

Ok so do I have to create other cases for revision 2,3,4 for upcasting to revision 5. something like this.

private IntermediateEventRepresentation potentialUpcast( final IntermediateEventRepresentation intermediateRepresentation ) {
		final SerializedType serializedType = intermediateRepresentation.getType( );
		if ( serializedType.getRevision( ).equals( "1" ) && relevantEvents.contains( serializedType.getName( ) ) ) {
			return intermediateRepresentation.upcastPayload( new SimpleSerializedType( serializedType.getName( ), "5" ), JsonNode.class, this::upcast );
		} 
        else if(serializedType.getRevision( ).equals( "2" ) && relevantEvents.contains( serializedType.getName( ) )) {
            return // dostuff
        }
        else {
			return intermediateRepresentation;
		}
	}

Hi,

That depends on your events and on the revisions you have in your event store. Basically you have to provide one or more upcasters to make sure that you can upcast each event in any revision within your event store to the current data structure. How you do this (one multi-functional upcaster, one upcaster for each event, one upcaster for each event and revision, …) is up to you.

Best regards

Nils

Hi,
it is not mandatory to create a single upcaster class for each revision, indeed.
The main advantage of having them all separate is for unit testing.

If you end up having 10 upcasters for a single event, I will argue that you need to spend a bit of time with your domain expert to understand better the domain and the problem that you are trying to solve, maybe with the help of techniques such as Event Storming or Event Modelling, before jump into action writing your code.
Keep in mind that each upcaster add complexity in the event sourcing, with an impact on your application performance.
To know more you can listen to the podcast by @Sara_Torrey recorded with Axon Framework Lead Developer @Steven_van_Beelen

2 Likes