Changes since 25.1.0-alpha12
Breaking changes
-
Enforce signal reads in computed signals and effects
Commit · Pull requestHelp detect cases where a value is assumed to update reactively even though it isn't by throwing an exception whenever an effect or computed signal doesn't depend on any signal value.
New features
-
Add signal bind methods for NativeDetails, HtmlObject, and HasStyle
Commit · Pull request -
Add custom equality checker support to ValueSignal
Commit · Pull request · IssueOptimize ValueSignal to skip updates when the new value equals the current value, and allow customization of equality logic. Changes: - Add SerializableBiPredicate<T, T> field for custom equality checking - Add constructor accepting custom equality checker (defaults to Objects::equals) - Update set() to skip updates when values are equal per equality checker - Update update() to use equality checker instead of reference equality - Add comprehensive tests for default and custom equality checkers.
-
Throw IllegalStateException when Signal.get() is called outside a reactive context
Commit · Pull request · IssueSignal.get() now throws when called outside a reactive context (effect, computed signal, untracked block, or transaction) to prevent accidental non-reactive reads like
new Span("Name: " + nameSignal.get())that silently return the value but never update. Users should use peek() for one-time reads. Key changes: - UsageTracker: add DELIBERATELY_UNTRACKED sentinel so untracked() sets a sentinel instead of removing the tracker, distinguishing "deliberately untracked" from "no tracking context" - AbstractLocalSignal/AbstractSignal: guard get() with isGetAllowed() check (shared signals also allow get() inside transactions) - ComputedSignal: remove peek() override so computed signals can be read outside reactive contexts via inherited AbstractSignal.peek() - Production code: use peek() where get() was called outside reactive contexts (Html, VaadinSession, SharedMapSignal.toString, Binder) -
Make shared signals use asynchronous signal trees
Commit · Pull request · IssueShared signals (SharedValueSignal, SharedListSignal, SharedMapSignal, SharedNodeSignal) now use LocalAsynchronousSignalTree instead of SynchronousSignalTree. This aligns with future clustered implementations where confirmation happens asynchronously via an event log. Key changes: - Add LocalAsynchronousSignalTree that dispatches confirm() on Vaadin's service executor - Adjust confirm() to skip observer notification when confirmed commands were at the head of the unconfirmed queue (no state change) As a side effect, all signals in a transaction must be from the same tree.
-
Add bindRequiredIndicatorVisible to HasValue / HasValueAndElement
Commit · Pull requestAllow all HasValueAndElement components to bind the required indicator visible state to a Signal, following the same pattern as bindReadOnly.
-
Add windowSizeSignal() to Page for reactive window size tracking
Commit · Pull requestAdds a read-only Signal to Page that automatically updates when the browser window is resized. Reuses the same JS resize listener infrastructure as addBrowserWindowResizeListener() via a shared ensureResizeListener() method.
Fixes
-
Revert invalid change
Commit · Pull request -
Remove git stash from pre-commit hook to prevent merge conflicts
Commit · Pull requestThe stash push/pop cycle caused merge conflicts when Spotless reformatted staged files, leaving the working tree in a broken state requiring manual resolution. The trade-off is that partial staging (git add -p) may now include unstaged formatting changes, which is cosmetic and recoverable.
-
Populate ActiveStyleSheetTracker during page load for CSS live reload without HotSwap Agent
Commit · Pull request · IssueActiveStyleSheetTracker was only populated by StyleSheetHotswapper.onInit(), which requires a HotSwap Agent. Without one, the tracker stayed empty and PublicResourcesLiveUpdater's file watcher silently skipped all CSS updates. Register active StyleSheet URLs during normal dev-mode page loading: - AppShellRegistry.createSettings() tracks AppShell stylesheets - UIInternals.addComponentDependencies() tracks component stylesheets Both paths are guarded by !isProductionMode() for zero production overhead. Also simplify the live reload integration test to rely on the file watcher instead of manually triggering reload via button clicks.
-
Allow signal.get() in Binder validators
Commit · Pull request · IssueSplit the conversion chain into executeConversionChain() (raw, used by the signal effect for dependency tracking) and doConversion() (always wrapped in untracked(), used by all other callers). Extract fireValidationEvents() so the effect can fire events directly. Guard trackUsageOfInternalValidationSignal() with isActive() to skip work inside untracked contexts.
-
IndexOutOfBoundsException when serializing arrays in JacksonSerializer
Commit · Pull request · IssueWhen serializing Java arrays, JacksonSerializer was using ArrayNode.set(i, value) on a newly created ArrayNode. In Jackson, set() expects an existing element at the given index, leading to an IndexOutOfBoundsException for new arrays. This change switches to ArrayNode.add(value) to correctly populate the array. Additionally, support for deserializing JSON arrays back into Java arrays was added to ensure symmetry in JacksonSerializer.
-
Update outer transaction read revision before publishing changes in StagedTransaction
Commit · Pull requestMove the outer.include() loop from commit() into commitTwoPhase(), between applyChanges() and publishChanges(). This ensures the outer RepeatableReadTransaction's read revision is updated before change listeners fire, so that downstream effects (like hasChanges()) can read the new value when signal.update() is used with a session-scoped fallback transaction.