Key UIData/UIRepeat per-row EVH state by clientId, not row index - #1034
Merged
Conversation
A nested iterating component is a single instance reused across the enclosing component's rows, so keying its per-row EditableValueHolder state by the bare row index made every enclosing row map to the same key and overwrite the previous one. Only the last enclosing row's submitted values survived: the rest were dropped silently, without conversion, validation, model update or a message. Key on getContainerClientId() instead, which is this component's clientId plus its current row index and therefore carries the enclosing rows' indices too. That is what _rowDeltaStates and _rowTransientStates key on, and what _rowStates itself keyed on before 6336caf. The positional EditableValueHolderState list, its deferred allocation and the flat iteration lists are unchanged; only the map key differs. Mojarra hit the same defect and resolved it the same way, see eclipse-ee4j/mojarra#5874 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
melloware
approved these changes
Jul 29, 2026
Member
|
Thanks! |
tandraschko
pushed a commit
that referenced
this pull request
Jul 30, 2026
A nested iterating component is a single instance reused across the enclosing component's rows, so keying its per-row EditableValueHolder state by the bare row index made every enclosing row map to the same key and overwrite the previous one. Only the last enclosing row's submitted values survived: the rest were dropped silently, without conversion, validation, model update or a message. Key on getContainerClientId() instead, which is this component's clientId plus its current row index and therefore carries the enclosing rows' indices too. That is what _rowDeltaStates and _rowTransientStates key on, and what _rowStates itself keyed on before 6336caf. The positional EditableValueHolderState list, its deferred allocation and the flat iteration lists are unchanged; only the map key differs. Mojarra hit the same defect and resolved it the same way, see eclipse-ee4j/mojarra#5874 Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> (cherry picked from commit c65bda2) # Conflicts: # api/src/main/java/jakarta/faces/component/UIData.java
Member
|
ported it to 4.1 |
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.
Problem
A
UIDataorUIRepeatnested inside another iterating component loses the submitted values of every enclosing row but the last — silently: no conversion, no validation, no model update, no message.Reproduced on a 5×10 grid (outer table over 5 groups, inner over 10 rows, 3 text inputs per row) by submitting a marker into every input and counting how many the response echoes back:
h:dataTableinh:dataTableui:repeatinui:repeath:dataTableThe 30 that survived were exactly the last outer row.
Cause
Regression from 6336caf ([perf] optimize UIData/UIRepeat state saving), which changed the per-row
EditableValueHolderstate map fromMap<String, …>keyed bygetContainerClientId(context)toMap<Integer, …>keyed by the bare row index.A nested iterating component is one instance reused across the enclosing rows, so the bare index makes every enclosing row map to the same key.
getContainerClientId()is the clientId plus the current row index, carrying both dimensions; the index key kept only one._rowDeltaStatesand_rowTransientStateswere never changed and still key on the clientId.Fix
Key
_rowStatesongetContainerClientId()again in both components. The precollected iteration lists, the positionalEditableValueHolderStatelist and its deferred allocation are untouched — only the key type and the two key expressions change.The optimisation is not being asked back. Measured against current
mainwith onlyUIData/UIRepeatreverted to their state before 6336caf, on the Mojarratest/perfsuite (Tomcat, 32 scenarios, two alternating rounds):Tests
UIDataTest.testNestedTableRowStateIsScopedPerOuterRowandUIRepeatTest.testNestedRepeatRowStateIsScopedPerOuterRow: a 2×2 nested grid, a distinct value per cell, iterate away and back, assert each cell kept its own. Both fail without the fix (expected: <v00> but was: <v10>) and pass with it. Fullapi+implsuite green, 1651 tests.Notes
4.1.xis needed: b4a4050 carries the same change there, so 4.1.x has the same defect. This PR targetsmainonly.🤖 Generated with Claude Code (Opus 5)