Polymorphic Aggregate Migration

Polymorphic aggregates allow you to define a hierarchy where subtypes inherit command and event sourcing handlers from their superclasses. For a detailed guide on how to model these, please refer to the modeling section.

Let’s take a look at the following example:

public abstract class Card {}

public class GiftCard extends Card {}

public class OpenLoopGiftCard extends GiftCard {}
public class RechargeableGiftCard extends GiftCard {}

In Axon Framework 4, polymorphic aggregates were often configured using Spring’s @Aggregate annotation on both the base and subclasses. When using the manual configuration API, you would use AggregateConfigurer.

In Axon Framework 5, you register the hierarchy through the EventSourcingConfigurer or the @EventSourcedEntity annotation:

  • Axon Framework 5 (Declarative)

  • Axon Framework 5 (AutoDetected)

  • Axon Framework 4

public class AxonConfig {
    // ...
    public void configure(EventSourcingConfigurer configurer) {
         configurer.registerEntity(
                EventSourcedEntityModule.declarative(String.class, GiftCard.class)
                        .messagingModel((configuration, builder) -> PolymorphicEntityMetamodel.forSuperType(GiftCard.class)
                                .addConcreteType(AnnotatedEntityMetamodel.forConcreteType(
                                        OpenLoopGiftCard.class,
                                        configuration.getComponent(ParameterResolverFactory.class),
                                        configuration.getComponent(MessageTypeResolver.class),
                                        configuration.getComponent(MessageConverter.class),
                                        configuration.getComponent(EventConverter.class)
                                ))
                                .addConcreteType(AnnotatedEntityMetamodel.forConcreteType(
                                        RechargeableGiftCard.class,
                                        configuration.getComponent(ParameterResolverFactory.class),
                                        configuration.getComponent(MessageTypeResolver.class),
                                        configuration.getComponent(MessageConverter.class),
                                        configuration.getComponent(EventConverter.class)
                                ))
                                .build())
        );
                                    // other phases (factory, etc.) omitted for brevity
    }
}

In most cases, you can rely on auto-detection of polymorphic entities by Axon Framework 5. Simply register the base type, and the framework will discover the subtypes automatically.

@EventSourcedEntity(
    concreteTypes = {
            OpenLoopGiftCard.class,
            RechargeableGiftCard.class
    }
)
public class GiftCard extends Card {
    // ...
}

public class AxonConfig {
    // ...
    public void configure(EventSourcingConfigurer configurer) {
        configurer.registerEntity(
                EventSourcedEntityModule.autodetected(String.class, GiftCard.class)
        );
    }
}
public class AxonConfig {
    // ...
    public void configure(Configurer configurer) {
        Set<Class<? extends GiftCard>> subtypes = Set.of(
            OpenLoopGiftCard.class,
            RechargeableGiftCard.class
        );

        configurer.configureAggregate(
            AggregateConfigurer.defaultConfiguration(GiftCard.class)
                               .withSubtypes(subtypes)
        );
    }
}