@OnChange, @OnInsert, @OnUpdate, @OnDelete, or @OnReplace. These annotations go on methods inside a @ChangeStream class.
Overview
There are two types of handler annotations:| Type | Annotations | Purpose |
|---|---|---|
| Generic | @OnChange | Catches all (or filtered) operation types |
| Typed | @OnInsert, @OnUpdate, @OnDelete, @OnReplace | Routes events by specific operation type |
Dispatch Priority
When an event arrives, FlowWarden resolves the handler in this order:- Typed handler matching the operation type (
@OnInsertfor INSERT,@OnUpdatefor UPDATE, etc.) @OnChangefallback — only if no typed handler matches, and the event passes theoperationTypesfilter
Typed handlers always take priority.
@OnChange is only invoked for operation types that have no dedicated typed handler in the class.@OnChange
Generic handler for all Change Stream event types. Acts as a catch-all when no typed handler matches.- Only one
@OnChangemethod is allowed per@ChangeStreamclass. - Signature must use the
CONTEXT_ONLYstyle —void handle(ChangeStreamContext ctx)orMono<Void> handle(ChangeStreamContext ctx).
Filtering by Operation Type
Use theoperationTypes attribute to restrict which events @OnChange handles:
operationTypes is empty (the default), all operation types are accepted.
Typed Handlers
@OnInsert
Called when a new document is inserted into the collection.@OnUpdate
Called when an existing document is updated.@OnDelete
Called when a document is deleted.@OnReplace
Called when a document is replaced entirely (e.g. viaMongoTemplate.save() on an existing document).
Rules for Typed Handlers
- At most one method per typed annotation per class (e.g. you cannot have two
@OnInsertmethods) - If no typed handler matches the event,
@OnChangeis used as fallback (if present) - If neither a typed handler nor
@OnChangematches, the event is silently skipped
Combining Annotations on the Same Method
You can place multiple typed annotations on a single method to handle several operation types with the same logic:@OnChange(operationTypes = {INSERT, UPDATE}), but uses the typed handler dispatch path (which takes priority over @OnChange).
Equivalence with @OnChange(operationTypes)
Equivalence with @OnChange(operationTypes)
These two approaches produce the same behavior:The key difference: typed handlers have higher dispatch priority than
@OnChange. If you also have a separate @OnChange fallback in the same class, the typed annotations will be resolved first.Supported Signatures
Parameter Styles
Typed handler methods (@OnInsert, @OnUpdate, @OnDelete, @OnReplace) support three parameter styles:
| Style | Signature | Description |
|---|---|---|
CONTEXT_ONLY | handle(ChangeStreamContext<T> ctx) | Access context; get the document via ctx.getFullDocument(). |
DOCUMENT_ONLY | handle(T doc) | Receive the deserialized document directly. |
DOCUMENT_AND_CONTEXT | handle(T doc, ChangeStreamContext<T> ctx) | Both the document and the context. |
@OnChange only supports CONTEXT_ONLY.
Return Types — Mode Exclusivity
Handler methods must use the return type that matches the configuredflowwarden.default-mode:
| Mode | Required Return Type | Description |
|---|---|---|
IMPERATIVE | void | Blocking handler. Mono<Void> is rejected at startup. |
REACTIVE | Mono<Void> | Non-blocking handler. void is rejected at startup. |
- Imperative (void)
- Reactive (Mono)
| Style | Signature |
|---|---|
CONTEXT_ONLY | void handle(ChangeStreamContext<T> ctx) |
DOCUMENT_ONLY | void handle(T doc) |
DOCUMENT_AND_CONTEXT | void handle(T doc, ChangeStreamContext<T> ctx) |
CompletableFuture, Flux, String) is rejected at startup.
Examples
Typed Handlers with @OnChange Fallback
This example handles INSERT, UPDATE, and DELETE with typed handlers, and uses@OnChange as a fallback for REPLACE events.
Combined Annotations with @Filter
From thesample-spring-mvc module — a handler that reacts to both INSERT and UPDATE with a client-side filter:
This works because both INSERT and UPDATE events have a
fullDocument available, which is required by @Filter. Combining @OnInsert @OnDelete with @Filter would fail at startup because DELETE events have no full document.Minimal — Single @OnChange
The simplest form: one handler for all event types.Event Capture for Testing
From theflowwarden-samples project — a reusable handler that captures events for test assertions:
Validation Errors
FlowWarden validates handler methods at startup. Here are the common errors:| Error | Cause | Fix |
|---|---|---|
| ”must have at least one handler method” | @ChangeStream class has no @OnChange, @OnInsert, etc. | Add at least one handler method. |
| ”must have exactly one @OnChange method” | Multiple @OnChange methods in the same class. | Keep only one @OnChange. |
| ”must have at most one @OnInsert method” | Duplicate typed handler for the same operation. | Keep only one per type. |
| ”must have at most one @OnUpdate method, found 2” | Two different methods have the same typed annotation. | Keep only one method per annotation type. You can combine multiple annotations on a single method instead. |
| ”uses a document-typed signature but documentType is Document.class” | Handler uses (T doc, ...) but no concrete documentType is set. | Set documentType = YourClass.class on @ChangeStream. |
| ”has invalid signature” | Method parameters don’t match any supported style. | Use one of the three supported signatures. |
| ”has unsupported return type” | Return type is not void or Mono<Void>. | Use void (imperative) or Mono<Void> (reactive). |
| “returns Mono but mode is IMPERATIVE” | Mono<Void> handler in IMPERATIVE mode. | Switch to void return type, or change flowwarden.default-mode to REACTIVE. |
| ”returns void but mode is REACTIVE” | void handler in REACTIVE mode. | Switch to Mono<Void> return type, or change flowwarden.default-mode to IMPERATIVE. |
See Also
@ChangeStream
The parent annotation that declares a Change Stream handler class.
Handler Signatures
Detailed reference for all supported method signatures.
ChangeStreamContext
The context object passed to every handler — access document, metadata, and operations.
@Filter
Server-side filtering to reduce the events reaching your handlers.

