x
and output zero or more new events of revision x + 1
. Moreover, upcasters are processed in a chain, meaning that the output of one upcaster is sent to the input of the next. This allows you to update events in an incremental manner, writing an upcaster for each new event revision, making them small, isolated, and easy to understand.NotePerhaps the greatest benefit of upcasting is that it allows you to do non-destructive refactoring. In other words, the complete event history remains intact.
RevisionResolver
, configured in the serializer. Axon provides several implementations of the RevisionResolver
:AnnotationRevisionResolver
checks for an @Revision
annotation on the Event payload.SerialVersionUIDRevisionResolver
uses the serialVersionUID
as defined by Java Serialization API.FixedValueRevisionResolver
always returns a predefined value. This is particularly useful when injecting the current application version.MavenArtifactRevisionResolver
to automatically use the project version.null
is returned.EventMessage
directly, but with an IntermediateEventRepresentation
. The IntermediateEventRepresentation
provides functionality to retrieve all necessary fields to construct an EventMessage
(and thus a upcasted EventMessage
too), together with the actual upcast functions. These upcast functions by default only allow the adjustment of the event's payload, payload type and additions to the event's metadata. The actual representation of the events in the upcast function may vary based on the event serializer used or the desired form to work with, so the upcast function of the IntermediateEventRepresentation
allows the selection of the expected representation type. The other fields, for example the message/aggregate identifier, aggregate type, timestamp etc. are not adjustable by the IntermediateEventRepresentation
. Adjusting those fields is not the intended work for an upcaster. As such, those options are not provided by the provided IntermediateEventRepresentation
implementations.Upcaster
interface for events in the Axon Framework works on a Stream
of IntermediateEventRepresentations
and returns a Stream
of IntermediateEventRepresentations
. The upcasting process thus does not directly return the end result of the introduced upcast functions, but chains every upcasting function from one revision to another together by stacking IntermediateEventRepresentations
. Once this process has taken place and the end result is pulled from them, that is when the actual upcasting function is performed on the serialized event.Conversion NoticeSometimes the event store can contain events in different serialized formats, since differingSerializer
implementations where used.During upcasting it is important to note what the format is of theIntermediateEventRepresentation
, as it influences the upcaster solution provided. To validate if the intermediate representation supports a given type, you can invokeIntermediateEventRepresentation#canConvertDataTo(Class<?>)
.
Upcaster
interface does not upcast a single event; it requires a Stream<IntermediateEventRepresentation>
and returns one. However, an upcaster is usually written to adjust a single event out of this stream. More elaborate upcasting setups are also imaginable. For example from one event to multiple, or an upcaster which pulls state from an earlier event and pushes it in a later one. This section describes the currently provided (abstract) implementations of event upcasters which a user can extend to add their own desired upcast functionality.SingleEventUpcaster
- a one-to-one implementation of an event upcaster. Extending from this implementation requires one to implement a canUpcast
and doUpcast
function, which respectively check whether the event at hand is to be upcasted, and if so how it should be upcasted. This is most likely the implementation to extend from, as most event adjustments are based on self contained data and are one to one.EventMultiUpcaster
- a one-to-many implementation of an event upcaster. It is mostly identical to a SingleEventUpcaster
, with the exception that the doUpcast
function returns a Stream
instead of a single IntermediateEventRepresentation
. As such, this upcaster allows you to convert a single event to several events. This might be useful if you for example have figured out you want more fine grained events from a fat event.ContextAwareSingleEventUpcaster
- a one-to-one implementation of an upcaster, which can store context of events during the process. Next to the canUpcast
and doUpcast
, the context aware upcaster requires one to implement a buildContext
function, which is used to instantiate a context which is carried between events going through the upcaster. The canUpcast
and doUpcast
functions receive the context as a second parameter, next to the IntermediateEventRepresentation
. The context can then be used within the upcasting process to pull fields from earlier events and populate other events. It thus allows you to move a field from one event to a completely different event.ContextAwareEventMultiUpcaster
- a one-to-many implementation of an upcaster, which can store context of events during the process. This abstract implementation is a combination of the EventMultiUpcaster
and ContextAwareSingleEventUpcaster
, and thus services the goal of keeping context of IntermediateEventRepresentations
and upcasting one such representation to several. This implementation is useful if you not only want to copy a field from one event to another, but have the requirement to generate several new events in the process.EventTypeUpcaster
- a full upcaster implementation dedicated to changing the event type. The EventTypeUpcaster
is an implementation of the SingleEventUpcaster
with predefined canUpcast
and doUpcast
functions to be able to change an event from one event type to another. This can be used to for example change the class or package name of an event with ease. To create an EventTypeUpcaster
, it is recommended to use the EventTypeUpcaster#from(String expectedPayloadType, expectedRevision)
and EventTypeUpcaster.Builder#to(upcastedPayloadType, upcastedRevision)
methods.What's a part of the context in a Context-Aware Upcasters?A context-aware upcaster allows you to collect state from previous events. As upcasters work on a stream of events, all that can ever belong to the context, is the state from that stream.However, this "stream of events" is not identical at all times. For example, when an aggregate is event-sourced, the event stream consists of aggregate instance-specific events. Furthermore, the stream of events starts from the tracking token's position for a Streaming Event Processor. Hence, the context contains different state depending on what's included in the event stream.
SingleEventUpcaster
).EventUpcasterChain
. The upcaster chain is what the EventStore
uses to attach all the upcast functions to the event stream.EventUpcasterChain
directly. Instead, consider the following snippets when it comes to registering upcasters:Order
annotation on upcasters. The numbers used in the annotation will dictate the ordering. The lower the number, the earlier it is registered to the upcaster chain:EventUpcasterChain
bean to the Application Context will tell Axon to configure it for your event source: