Course Catalog Example

A runnable example application exercises the transformations from these pages end to end. The university-message-transformation demo models a course catalog that has evolved through several event-schema versions: historic events stay in the store exactly as they were written, and a chain of transformations lifts each one to its current shape on the read path.

See the university-message-transformation example for the full source. Its README covers running it in-memory or against Axon Server (optionally reporting to AxonIQ Platform), an interactive shell to play around with, and test-suite examples.

What it demonstrates

The demo composes a chain of transformations, each illustrating a technique covered here:

Transformation Change Technique

CourseOfferedToCoursePublished

the legacy CourseOffered event is renamed to CoursePublished

a rename whose output then flows through the CoursePublished version chain

CoursePublishedV1ToV2

a single capacity field becomes minCapacity and maxCapacity

a single structural transformation on an untyped JsonNode

CoursePublishedV2ToV3

minCapacity/maxCapacity are wrapped into a range, producing the current CoursePublished event

a typed mapper to the current event that, with the previous transformation, shows chaining in version order

StudentRegisteredV1ToV2

separate firstName and lastName become a single fullName

the TypeReference overload, with no Jackson dependency in user code

StudentRegisteredV2ToV3

a region field, absent when the events were written, is backfilled

a mapper that reads from the ProcessingContext

SystemAnnouncementLegacyUplift

an unversioned legacy event is lifted onto 1.0.0

matching unversioned events stored as 0.0.1, see Upcaster migration

WelcomeMessageBetaCleanup

every 0.x beta version folds up to 1.0.0

a version-only predicate scoped with declaringFromTypes

SystemHeartbeatDrop

SystemHeartbeat pings are removed from the read stream, so the projection’s heartbeat count stays at zero

a drop, one event in and none out

A further class, WelcomeMessageBetaCleanupWithoutPreFilter, expresses that last rule without declaringFromTypes(…​) to contrast the two predicate-from styles. It is not registered in the chain.

The chain is assembled in CourseCatalogTransformations and registered as an EventTransformerChain component, as shown in Configuring transformations.