Class AddCommandAnnotation

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

public class AddCommandAnnotation extends org.openrewrite.ScanningRecipe<AddCommandAnnotation.Accumulator>
Scans for methods annotated with @CommandHandler and annotates their command parameter types with @Command.

Routing-key lifting: If the command class has a field — or a Java record component, or a Kotlin data class primary constructor parameter — annotated with @RoutingKey, that annotation is removed and replaced with @Command(routingKey = "fieldName") on the class. Likewise, if the field carries @TargetAggregateIdentifier (AF4) or its post-rename AF5 successor @TargetEntityId, the field name is lifted onto @Command#routingKey; unlike @RoutingKey, those annotations are preserved on the field.

Precedence: When a class declares both an explicit @RoutingKey field and a @TargetAggregateIdentifier / @TargetEntityId field, the explicit @RoutingKey field wins regardless of declaration order, matching AF4 routing semantics where @RoutingKey takes precedence over the target-identifier annotations.

Idempotent updates: If the class already carries a @Command annotation whose routingKey attribute is missing or blank, the recipe adds the attribute rather than skipping the class. A @Command with a non-empty routingKey is left untouched.

Ordering: Java records and class fields complete the lift in a single OpenRewrite cycle: the recipe walks J.ClassDeclaration.primaryConstructor (records) and J.ClassDeclaration.body (fields) directly, and crucially performs the @RoutingKey removal AFTER JavaTemplate.apply adds the class-level @CommandJavaTemplate.apply walks the visitor's cursor (still pointing at the un-modified class declaration) and would otherwise discard any child mutations applied beforehand. Kotlin data class primary-constructor parameters live outside J.ClassDeclaration (the Kotlin parser keeps them on a sibling Kotlin LST node), so for Kotlin the recipe falls back to the visitVariableDeclarations hook to capture the parameter name and to strip the now-orphaned @RoutingKey annotation in a second cycle.

Both AF4 (org.axonframework.commandhandling.CommandHandler) and AF5 (org.axonframework.messaging.commandhandling.annotation.CommandHandler) FQNs are matched so the recipe is safe to run before or after Axon4ToAxon5Messaging.

Since:
5.1.1
Author:
Mateusz Nowak
  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    static class 
     

    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