lukaszlenart opened a new pull request, #1937:
URL: https://github.com/apache/struts/pull/1937

   Fixes [WW-5740](https://issues.apache.org/jira/browse/WW-5740). Docs: 
apache/struts-site PR linked below.
   
   ## Problem
   
   A field reached through a `visitor` validator (`user.name`) had its 
`data-msg-*` text resolved through `DelegatingValidatorContext(action)` — the 
action's bundles only — while `VisitorFieldValidator.validateObject` validates 
it with a composite provider over the visited class and the action, and pushes 
the visited instance for `${...}`. A `<message key="name.required"/>` living in 
`ConstraintUser.properties` rendered as the raw key.
   
   ## What changed
   
   - **`Form`** gives each unwrapped visitor validator, at unwrap time, the 
context validation gives it: `DelegatingValidatorContext(parent, 
CompositeTextProvider([each visited level innermost first, parent]), parent)` — 
line for line `VisitorFieldValidator.validateObject`. Providers are class-based 
(runtime class when the instance exists), so a form rendered before the visited 
object exists still finds the bundle. The wrapper carries the whole visited 
chain (classes + OGNL paths, outermost first); visitor validators are cached 
per visited path rather than per class, since two visitors over one class must 
not share the instances the context is set on.
   - **`Form.getValidatedObject(name)`** (new, `@since 7.4.0`) returns the 
innermost visited instance when the whole chain exists and exactly one visited 
path claims the field; otherwise `null` and the caller uses the action. The 
lookup re-pushes the validation-time stack — the action plus, for a 
`ModelDriven` action whose interceptor pushed it, the model instance taken from 
the stack (identity-checked) — so an `<s:iterator>`/`<s:push>` frame above the 
action cannot shadow the object validation used.
   - **`UIBean`** pushes the visited chain (popped by the existing 
`restoreStackDepth`) and hands the provider that object, so `${...}` and 
`messageParams` read the visited bean as during validation.
   - **`HtmlConstraintProvider`**: no signature change; the third parameter's 
Javadoc now says what object it is.
   
   ## Review history
   
   Eight passes (security + seven `/code-review`), each landing as its own 
commit; the significant ones: doubly-nested visitors chained through every 
level; ambiguous fields (two `appendPrefix="false"` visitors, or visitor-nested 
next to direct) fall back to the action; visited objects read off the action 
rather than the top of the render stack; partial chains hand over the action; 
the model is the instance the interceptor pushed, identity-checked, never 
`getModel()` re-invoked — the HIGH found on pass six was `modelDriven` being in 
`defaultStack`, so "interceptor configured" alone promoted iterator elements to 
models.
   
   ## Known limitations, stated on purpose
   
   - The visitor's own `<message>` (which `AppendingValidatorContext` prepends 
to submitted errors, "User: Name is required") is not reflected in 
`data-msg-*`. It is error-display decoration rather than the field's message; 
the deprecated JS validator never applied it either.
   - Validators come from the form's *target* action, visited instances from 
the *rendering* action's stack. When the two differ (`list` renders `<s:form 
action="save">`), messages resolve against the rendering action's objects. 
Pre-existing; the previous code resolved against the rendering action too.
   - The deprecated JS path shares the cached validator instances, so under the 
html5 theme with `validate="true"` a visitor-nested field's JS message now also 
resolves through the visited bundle once the field has been rendered. An 
improvement for that case, but it is render-order dependent.
   
   ## Tests
   
   `mvn test -DskipAssembly -pl core`: 3376 tests, 0 failures. Every production 
change went red first (the initial symptom, the raw `name.required`, is the 
first RED). Fixtures: 
`ConstraintUser.properties`/`AdminConstraintUser.properties`, 
`ConstraintAddress`, `ModelDrivenConstraintAction`, and a 
`modelDrivenConstraintAction` config in `TestConfigurationProvider`.
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to