Class AddEventTagAnnotation

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

public class AddEventTagAnnotation extends org.openrewrite.ScanningRecipe<AddEventTagAnnotation.Accumulator>
Adds @EventTag(key = "<EntitySimpleName>") to the aggregate-identifier field of every event class used in @EventSourcingHandler methods.

The recipe runs in two phases:

  1. Scan - visits entity classes (annotated with @Aggregate, @EventSourced, or @EventSourcedEntity) and records the event payload type for every event used in the entity, together with the entity's identifier field name and the entity's simple class name. Events are discovered from two sources: (1) the first parameter of each @EventSourcingHandler method, and (2) the first argument of every AggregateLifecycle.apply(...) call site in the entity body. The second source catches events that are published but never re-sourced in this entity (a valid AF4 pattern that would otherwise miss the @EventTag treatment).
  2. Edit - for every event class recorded in the scan, picks the field that should carry @EventTag(key = "<EntitySimpleName>"), trying each of the following until one matches:
    1. a field named exactly the entity's identifier field name;
    2. a field whose declared type matches the identifier's type (when known) and whose name is a case-insensitive suffix relationship of the identifier field name - e.g. entity id giftCardId against an event field named id or cardId, annotated with a // TODO(axon4to5): comment asking a human reviewer to verify the choice;
    3. a field whose name matches (case-insensitively) a @TargetAggregateIdentifier/ @TargetEntityId field found on some other class in the same package - typically a command routing to this entity - with the same type-compatibility check, annotated with the same // TODO(axon4to5): comment;
    4. otherwise, the first declared field, annotated anyway (so the event isn't left without a tag) with the same // TODO(axon4to5): comment.
    Only an exact name match is certain, so every weaker match is flagged for review.

Child entities declared on a parent via @AggregateMember/@EntityMember are followed as well: each event used in a child entity's @EventSourcingHandler (or apply(...) call) is tagged with the parent entity's tag, so it is sourced into the parent's stream. This preserves the single event stream an Axon Framework 4 aggregate shared with its members. The same field-matching priority (exact name, then type-plus-name-similarity, then sibling command alias, then first field, the last three with a // TODO(axon4to5): comment) applies to child events.

Must run before @AggregateIdentifier is removed (i.e. before the RemoveAnnotation step inside Axon4ToAxon5Modelling), so that the annotation is still present for the scan.

What the LLM must still do: verify the selected field is truly the aggregate identifier wherever a // TODO(axon4to5): comment was added, and adjust key if the entity simple name differs from the intended tag name.

Since:
5.1.1
Author:
Mateusz Nowak
  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    static class 
    Maps event-class FQN -> scan result needed to place @EventTag.

    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