Class MigrateAggregateDeadlineHandler

java.lang.Object
org.openrewrite.Recipe
org.openrewrite.ScanningRecipe<MigrateAggregateDeadlineHandler.Accumulator>
org.axonframework.migration.MigrateAggregateDeadlineHandler
All Implemented Interfaces:
Cloneable

public class MigrateAggregateDeadlineHandler extends org.openrewrite.ScanningRecipe<MigrateAggregateDeadlineHandler.Accumulator>
Replaces the Axon Framework 4 @DeadlineHandler of an aggregate with the Axon Framework 4 @CommandHandler that receives the deadline once it fires.

On the Axoniq Framework legacy module, a deadline scheduled for an aggregate scope fires as a command named <aggregateType>.<deadlineName>, carrying the deadline's payload, or the deadline name when it has none. The aggregate type is the one Axon Framework 4 stored with the deadline: the type of the aggregate's @AggregateRoot or @Aggregate annotation, or its simple class name otherwise. The recipe replaces a handler with a deadlineName with @CommandHandler(commandName = "<aggregateType>.<deadlineName>"), keeping its parameters and any payloadType. A handler without a payload keeps receiving the deadline without one, whether or not the deadline carries a payload, as the command name alone routes it. A deadline name given as a constant is resolved over all sources.

A handler without a deadlineName received every deadline with its payload type in Axon Framework 4. The recipe replaces it with a @CommandHandler without a commandName, which receives the command named after that payload type. The legacy module dispatches a deadline under that name when no handler receives the command named after the deadline, logging a warning, so the handler keeps receiving every deadline with its payload type. A // TODO(axon4to5): marker asks to name the command after the deadline instead.

The recipe uses the Axon Framework 4 @CommandHandler on purpose: the Axon Framework 5 upgrade that runs afterwards moves it to the Axon Framework 5 package and migrates the handler like any other aggregate command handler. The deadline payload class is left untouched, since the target entity is resolved from the deadline's aggregate scope.

Where the recipe cannot name the command, it leaves a // TODO(axon4to5): marker and keeps the @DeadlineHandler:

  • a handler that names neither a deadline nor a payload type handled every deadline of the aggregate, and a handler without a deadline name whose payload type is Object, an interface or an abstract class handled every deadline with a payload of that type;
  • a handler without a deadline name whose payload type another @CommandHandler of the class handles, which a deadline dispatched under that payload type would reach instead;
  • a deadline name or aggregate type given as an expression that is no literal or resolvable constant;
  • a handler in a subclass of an annotated aggregate class: Axon Framework 4 stored the type of the polymorphic aggregate's root, which the subclass does not declare;
  • a handler in an unannotated class that is abstract or extended by another class of the sources: Axon Framework 4 stored the type of the aggregate extending it;
  • a handler of a member entity: Axon Framework 4 delivered a fired deadline to the aggregate root and to every member entity, while a command reaches an entity in a collection only through a routing key.
It also marks two handlers of one class that receive the same command, which Axon Framework 4 told apart by payload type, and a DeadlineMessage parameter, which does not match the command message that now arrives.

The recipe rewrites Java and Kotlin aggregates. Saga classes, which keep their @DeadlineHandler on the legacy module, are left alone. The recipe is idempotent.

Since:
5.4.0
Author:
Mateusz Nowak
  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    static class 
    What the scanning phase learns about the source classes.

    Nested classes/interfaces inherited from class org.openrewrite.Recipe

    org.openrewrite.Recipe.Builder, org.openrewrite.Recipe.DelegatingRecipe
  • Field Summary

    Fields inherited from class org.openrewrite.Recipe

    contributors, examples, PANIC
  • Constructor Summary

    Constructors
    Constructor
    Description
     
  • Method Summary

    Modifier and Type
    Method
    Description
     
     
    getInitialValue(org.openrewrite.ExecutionContext ctx)
     
    org.openrewrite.TreeVisitor<?,org.openrewrite.ExecutionContext>
     
    org.openrewrite.TreeVisitor<?,org.openrewrite.ExecutionContext>
     

    Methods inherited from class org.openrewrite.ScanningRecipe

    clone, generate, generate, getAccumulator, getVisitor

    Methods inherited from class org.openrewrite.Recipe

    addDataTable, aggregateDataTableDescriptors, builder, buildRecipeList, causesAnotherCycle, createRecipeDescriptor, equals, getContributors, getDataTableDescriptors, getDescriptor, getEstimatedEffortPerOccurrence, getExamples, getInstanceName, getInstanceNameSuffix, getJacksonPolymorphicTypeTag, getMaintainers, getName, getRecipeList, getTags, hashCode, maxCycles, noop, onComplete, run, run, run, setContributors, setExamples, validate, validate, validateAll, validateAll, withOptions

    Methods inherited from class java.lang.Object

    finalize, getClass, notify, notifyAll, toString, wait, wait, wait