Port/axon 5.1.x main#4617
Merged
Merged
Conversation
…es (#4558) Split the monolithic axon-5/api-changes.md into 12 focused files under axon-5/api-changes/, easier to process by people and AI Agents.
…Framework 4.x to Axoniq Framework 5.1.0
…n recipes and tests
…d BOM dependencies
…n 4.x to 5.x migration - Add `ConfigureEventSourcedAnnotationKotlinTest` to verify Kotlin-specific behaviors in migration recipes. - Introduce `ConvertCommandHandlerConstructorToCompanionObject` recipe to rewrite Kotlin `@CommandHandler` constructors into companion object methods meeting Axon 5.x requirements. - Add `ConvertCommandHandlerConstructorToCompanionObjectTest` to validate the recipe. - Add `MigrateAggregateTestFixtureSetupKotlinTest` to confirm Kotlin-compatible test fixture setup migration with proper class literal handling. - Replace fully qualified references with simple imports for `@CommandHandler` and `EventAppender`. - Update Kotlin migration recipes to ensure imports are correctly added for compatibility with Axon 5.x. - Introduce Kotlin upgrade step in migration YAML to support dependency and plugin alignment with Kotlin 2.x. - Improve handling of `CommandHandler` in companion object transformations to prevent import clashes during migration. - Introduce `AddEventTagAnnotationKotlinTest` to validate annotation of Kotlin primary constructor parameters. - Update `AddEventTagAnnotation` recipe to handle Kotlin-specific constructs such as `data class` primary constructors and `val/var` fields. - Improve annotation handling for Kotlin sources to ensure `@EventTag` is correctly applied and formatted. - Add test to validate fallback annotation placement for mismatched Kotlin field names. - Refactor `AddEventTagAnnotation` to properly handle Kotlin `data class` field declaration order. - Fix `isFirstFieldInClass` implementation to ensure correct field lookup in Kotlin and Java classes.
Closes the Gradle gap in `axon-migration` so the BOM rename + version
pin works end-to-end on Maven *and* Gradle projects (Groovy DSL,
Kotlin DSL, plain `platform(...)`, Spring Dependency Management
`mavenBom(...)`, and the Cinema-style `extra["axonFrameworkVersion"]`
+ `${property("...")}` indirection).
- Ship `migration/init.gradle` and document the Gradle invocation
(`gradle rewriteRun --init-script ...`) in the module README.
- Compose `gradle.ChangeManagedDependency` and
`gradle.ChangeExtraProperty` into the BOM YAMLs so Spring DM imports
and Groovy `ext.*` version properties get rewritten alongside the
existing Maven and `gradle.ChangeDependency` legs.
- Add `MigrateKotlinDslBomImport`, a small Kotlin-DSL-only recipe that
fills two upstream gaps: `SpringDependencyManagementPluginEntry`
doesn't extract version variables from `K.StringTemplate` whose
embedded expression is `property("...")`, and `ExtraProperty` doesn't
match the Kotlin-subscript `extra["..."] = "..."` shape. The recipe
rewrites the `groupId:artifactId:` prefix in `mavenBom(...)` while
preserving the `${property(...)}` indirection, and updates the
matching `extra["..."]` literal in the same pass.
- Cover the new Gradle paths with `Axon4ToAxon5BomGradleTest` (Groovy
+ Kotlin DSL, both free and commercial legs, including the
Cinema-style fixture). Tests attach a synthetic `GradleProject`
marker rather than spinning up a Gradle daemon via `withToolingApi()`,
keeping them lightweight (no `gradle-tooling-api` test dep needed).
- Expand annotation rewrites: add `@AggregateRoot` → `@EventSourcedEntity`, and clarify the removal of `@AggregateIdentifier` in favor of `tagKey` + `@EventTag`. - Document unconditional removal of `@CreationPolicy`, including `AggregateCreationPolicy`, and explain handling for `CREATE_IF_MISSING` and `ALWAYS`. - Provide additional guidance on lifted `@RoutingKey` and placement of `@EntityCreator` in constructors.
…nTestFixture` cleanup - Introduce `AddAxonTestFixtureTearDown` recipe to automatically generate an `@AfterEach tearDown()` method calling `fixture.stop()`, ensuring proper lifecycle management for `AxonTestFixture` in JUnit 5 tests. - Skip classes with existing `@AfterEach` methods or methods named `tearDown` to avoid duplication. - Limit changes to Java sources only; Kotlin support to be addressed separately. - Add comprehensive tests to verify correct migration behavior and idempotence.
…@InjectEntity` in GiftCard example Replace incorrect annotation in migration guide example to ensure proper entity injection.
fix(docs/migration-paths): update annotation from `@InjectState` to `@InjectEntity` in GiftCard example
The way a ComponentDescriptor describes a certain component, and whether it fits in a String or not, is entirely implementation dependent. Therefore, the describe() method should not be placed on the ComponentDescriptor interface.
Co-authored-by: Laura Devriendt <94172218+laura-devriendt-lemon@users.noreply.github.com>
…describe Remove describe method from ComponentDescriptor interface.
Rework snapshotting to allow single request snapshot + events streams
Replace placeholder `@author Axon Framework Team` and `@since 5.2.0` across all migration recipe classes with the correct values (`@author Mateusz Nowak`, `@since 5.1.1`). Also renames the test class `Axon4ToAxon5TestTest` to `Axon4ToAxon5TestFixtureTest` to read more naturally (reviewer suggestion); the corresponding file move ships in the same change so the new file is compilable at HEAD.
The Gradle init script was missing the standard Axon Framework header. Aligns with the rest of the module.
…ming into umbrella - `axon4-to-axon5-extension-tracing-opentelemetry.yml`: reduced to a placeholder no-op. Revisioning of the distributed-tracing extension is slated for a later release (issue #3594); doing the package move now would land ahead of the AF5 integration. - `axon4-to-axoniq5-event-streaming.yml`: corrected the description. `MultiStreamableMessageSource` has existed since AF 4.2; the new Axoniq Framework 5 module consolidates that pattern rather than introducing a wholly new concept without an AF4 counterpart. - `axon4-to-axoniq5-postgresql.yml`: removed entirely. The Axoniq PostgreSQL connector is new in AF5 with no AF4 source to rewrite, so an OpenRewrite recipe adds no value. README updated accordingly. - `axon4-to-axoniq5.yml`: wired `Axon4ToAxoniq5EventStreaming` into the commercial umbrella so the placeholder runs in the right order once it gains class-level mappings.
…all sites `AddEventTagAnnotation`'s scanner previously discovered event payload types from `@EventSourcingHandler` method parameters only. That misses a valid AF4 pattern: an event published via `AggregateLifecycle.apply` but never re-sourced in the entity (no matching `@EventSourcingHandler`). Without `@EventTag`, AF5 cannot determine the aggregate-id tag for that event at runtime. The scanner now also walks `AggregateLifecycle.apply(...)` invocations anywhere in the entity body and adds the first argument's payload type to the accumulator alongside the handler-based entries. The two sources union into the same map, so events that are both applied AND sourced remain handled exactly as before. New test `Axon4ToAxon5EventSourcingTest#taggsEventPublishedViaApply\ EvenWithoutEventSourcingHandler` covers the apply-but-not-sourced case.
…ension tests - BOM tests: bump sample starting version from 4.11.0 to 4.13.0 to match the current AF4 LTS line. - Reactor / spring-aot extension tests: bump sample version to 4.12.0 (the latest release of each extension on Maven Central). - Micrometer extension test: replace `GlobalMetricRegistry` (which does not exist in AF5) with `MessageCountingMonitor` so the asserted package rename references a class that actually ships in the AF5 metrics-micrometer module.
…chInterceptor` signatures `MessageHandlerInterceptor.handle(UoW, InterceptorChain) -> Object` becomes `interceptOnHandle(M, ProcessingContext, MessageHandlerInterceptorChain<M>) -> MessageStream<?>` (and likewise for the dispatch interface). The method body is intentionally left untouched: references to the dropped `unitOfWork` / `interceptorChain` / `messages` parameters turn into unresolved-symbol compile errors, surfacing every call site that needs human review. A class-level `// TODO #LLM` comment points to the migration path doc. The signature swap goes through a sub-parsed stub class so the rewriter can take real `J.MethodDeclaration` LST nodes for the new return type, name, and parameter list. The unused `UnitOfWork` import is force-removed even though the body still references its identifier — the body's `uow.X(...)` is a compile error anyway, and the user's IDE will clean up further unused imports during the manual body migration. Lifecycle-hook semantics (`onCommit` vs `runOnAfterCommit`, no AF5 equivalent for `onRollback`) and the `interceptorChain.proceed()` → `chain .proceed(message, context)` shift are intentionally NOT mechanized — a blind rewrite would silently land semantically wrong code in non-trivial interceptors. Scoped to fire only on classes that actually carry the AF4 `handle` method, so empty-body fixtures and abstract bases stay untouched.
…ng `AppendCondition` calculated from sourcing Allow users to control the AppendCondition used at commit time, beyond what automatic sourcing provides. This enables two primary use cases: 1. Appending without sourcing — enforcing uniqueness constraints without first sourcing events (e.g., ensuring a course name is unique by checking that no matching event exists since ORIGIN). 2. Narrowing (or broadening) the append condition — sourcing broad criteria for state but restricting which events are considered conflicting at commit time. Production changes: - AppendCondition: add replacingCriteria(EventCriteria) abstract method that preserves the consistency marker while replacing the criteria. Named "replacingCriteria" rather than "withCriteria" (as originally planned) because the interface already has a static factory method withCriteria(EventCriteria) and Java prohibits a static and abstract instance method with the same signature on a sealed interface. - NoAppendCondition: both wither methods (withMarker, replacingCriteria) now return DefaultAppendCondition instead of throwing. withMarker previously threw UnsupportedOperationException, but havingAnyTag() with a real marker is a valid, useful condition meaning "any event after this marker is a conflict." This makes NoAppendCondition composable (e.g., AppendCondition.none().withMarker(m) works). - DefaultAppendCondition: implement replacingCriteria mirroring the existing withMarker pattern (returns this if criteria unchanged). - EventStoreTransaction: add overrideAppendCondition(UnaryOperator) interface method. Input is AppendCondition.none() when no sourcing happened; returning none() bypasses conflict detection. Multiple calls compose (each receives the previous call's output). - DefaultEventStoreTransaction: implement override using a ResourceKey stored in ProcessingContext (consistent with appendConditionKey, eventQueueKey, appendPositionKey). Uses updateResource for atomic composition. Override applied in attachAppendEventsStep after marker resolution but before appendEvents, with DEBUG logging. - InterceptingEventStore: delegate overrideAppendCondition through InterceptingEventStoreTransaction. Test coverage: - DefaultAppendConditionTest: 2 tests for replacingCriteria - NoAppendConditionTest: 3 tests replacing the old throwing test, verifying composability of withMarker and replacingCriteria - DefaultEventStoreTransactionTest: 7 unit tests covering override without sourcing, after sourcing, chaining, criteria replacement, bypass, normal flow, and null rejection - StorageEngineBackedEventStoreTestSuite: 3 integration tests covering append-without-sourcing with conflict detection, narrowed criteria avoiding false conflicts, and bypass via none() (cherry picked from commit f89b691)
…ltEventStoreTransaction` (cherry picked from commit 526a252)
…veAppendCriteria method (cherry picked from commit 94b5990)
… integration tests Replace generic CourseUpdated with CourseCreated, StudentSubscribedToCourse, and StudentUnsubscribedFromCourse event types to better illustrate real-world use cases: - shouldAppendWithOverriddenConditionWithoutSourcing: course name uniqueness - narrowedCriteriaShouldAvoidFalseConflict: subscription/unsubscription narrowing - overrideReturningNoneShouldBypassConflictDetection: duplicate course name bypass Add sourceCount() helper to avoid CourseUpdated-specific payload conversion. (cherry picked from commit 28616b9)
… vs Aggregate hierarchy
The OverrideAppendCondition integration tests use DCB-specific patterns
(ORIGIN-based uniqueness, criteria narrowing by event type, conflict bypass)
that are not supported by aggregate-based storage engines. The aggregate-based
JPA engine uses sequence-number conflict detection via unique constraints,
ignoring AppendCondition criteria entirely.
Introduce a test suite hierarchy:
StorageEngineBackedEventStoreTestSuite (common: sourcing, streaming, tokens, conflicts)
├── DcbBasedStorageEngineBackedEventStoreTestSuite (DCB: overrideAppendCondition tests)
│ ├── InMemoryStorageEngineBackedEventStoreTest
│ └── AxonServerStorageEngineBackedEventStoreIT
└── AggregateBasedStorageEngineBackedEventStoreTestSuite (aggregate: placeholder)
└── AggregateBasedJpaStorageEngineBackedEventStoreIT
The 3 OverrideAppendCondition tests and DCB event records (CourseCreated,
StudentSubscribedToCourse, StudentUnsubscribedFromCourse) move from the base
suite to DcbBasedStorageEngineBackedEventStoreTestSuite. The base suite
exposes eventStore, awaitLatch, and RESOLVER as protected for subclass access.
(cherry picked from commit 8f0cd43)
[Port | #4594] Validate `ProcessingContext` is committed in `SimpleQueryBus` on `emitUpdate`, `completeSubscriptions`, and `completeSubscriptionsExceptionally` invocations
Move AF4 dependencies inside a profile. The release flow will otherwise spot the framework dependencies, which have the same groupId, and expect the version of those dependencies to align with the version to be released.
Combine all the ListAppender using tests. If the tests are spread out, they will interfere with one another and fail.
…es-under-profile Move AF4 dependencies inside profile for `axon-migration` module
Combine all the `ListAppender` using Snapshotting tests in single `@Nested` class
Copy AF4 dependencies during generate-test-resources. By doing so, we ensure that the release process cannot find the AF4 dependencies, on which it will trip, because we didn't upgrade the versions to the release version.
…gh-copy-in-build-plugin Copy AF4 dependencies during generate-test-resources
…oblem Axon4ToAxon5BomTest and Axon4ToAxon5BomGradleTest required OpenRewrite to resolve axon-framework-bom and axoniq-framework-bom at the to-be-released version. During a Maven release those artifacts don't exist yet, causing the tests to hang for a long time. The BOM coordinate rename is a mechanical text transformation driven entirely by the recipe YAML definitions; there is no custom logic to test. Testing that an existing OpenRewrite recipe executes correctly is not the responsibility of this module.
ConfigurerModule and ProcessingGroup both live in axon-configuration, not axon-messaging. Without it on the test classpath, OpenRewrite cannot resolve their types and Axon4ToAxon5CommonTest fails with "LST contains missing or invalid type information".
…-test fix(migration): remove BOM tests that fails due to chicken-and-egg problem
Add release notes for the 5.1.1 release to the reference guide
|
MateuszNaKodach
approved these changes
May 28, 2026
Contributor
MateuszNaKodach
left a comment
There was a problem hiding this comment.
I scanned it and I hope it's OK!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Port of 5.1.x development to main, covering:
@InjectStateto@InjectEntityin GiftCard example #4576EventStoreTransaction- allow overridingAppendConditioncalculated from sourcing #4291SnapshotTriggerDefinitioninto@Snapshottingannotation #4599axon-migrationmodule #4606ListAppenderusing Snapshotting tests in single@Nestedclass #4607Conflicts: