This is an automated email from the ASF dual-hosted git repository. lukaszlenart pushed a commit to branch feature/WW-5695-html5-constraint-validation in repository https://gitbox.apache.org/repos/asf/struts.git
commit 510f31acbfedecdc4a361a2eccd5d0c92574c5d1 Author: Lukasz Lenart <[email protected]> AuthorDate: Mon Aug 24 19:19:44 2026 +0200 WW-5695 docs(validation): correct the UIBean hook point and control-type resolution Reading the code turned up two errors in the approved design. evaluateExtraParams() is the last statement of evaluateParams(), and that is where TextField sets attributes.type. The hook cannot sit next to the tagNames block as written, because at that point no text field has a resolved type and every one of them would look like OTHER. It moves to the end of the method. attributes.type is set by TextField and nothing else on the input path, so the control type cannot come from the attribute map alone. Adds a getControlType() component hook with four overrides; Checkbox, Radio, File and Hidden fall through to OTHER, which emits nothing and is correct for all four. Co-Authored-By: Claude Opus 5 <[email protected]> --- ...026-08-24-html5-constraint-validation-design.md | 35 ++++++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/docs/superpowers/specs/2026-08-24-html5-constraint-validation-design.md b/docs/superpowers/specs/2026-08-24-html5-constraint-validation-design.md index 58ed7f93b..5f572b2dd 100644 --- a/docs/superpowers/specs/2026-08-24-html5-constraint-validation-design.md +++ b/docs/superpowers/specs/2026-08-24-html5-constraint-validation-design.md @@ -175,14 +175,43 @@ Defaults to `false` in `default.properties` for 7.4.0 and `true` for 8.0.0. Off by default matters: the `html5` theme shipped in 7.2.x, so emitting `required` on upgrade would start blocking submits on forms that render unchanged today. The 8.0.0 flip lands in a major with a migration entry. +### Resolving the control type + +`attributes.type` is set by `TextField.evaluateExtraParams` (`TextField.java:91`) and by nothing else on the +input path — `TextArea`, `Select`, `Checkbox`, `File`, `Hidden` and `Radio` have no `type` attribute at all. +So the control type cannot be read from the attribute map alone; it needs a component-level hook: + +```java +protected HtmlControlType getControlType(); // UIBean, returns OTHER +``` + +Overridden in four places, which is all that is needed: + +| Component | Returns | +|---|---| +| `UIBean` (base) | `OTHER` — supports nothing, so unknown controls emit no constraints | +| `TextField` | `HtmlControlType.from(getAttributes().get("type"))`, defaulting to `TEXT` when absent, matching `text.ftl`'s `attributes.type!"text"` | +| `Password` | `PASSWORD` — it extends `TextField` but its template hardcodes the type | +| `TextArea` | `TEXTAREA` | +| `Select` | `SELECT` | + +`Checkbox`, `Radio`, `File` and `Hidden` deliberately get no override. They fall through to `OTHER`, which +emits nothing — the correct answer for all four. `ComboBox` extends `TextField` and correctly inherits `TEXT`. + ### `UIBean` hook -`UIBean.evaluateParams` already resolves `final Form form = findAncestor(Form.class)` and appends to -`tagNames`. Immediately after that block, when the constant is on and a form was found: +`UIBean.evaluateParams` resolves `final Form form = (Form) findAncestor(Form.class)` at `UIBean.java:824` +and appends to `tagNames` just below it. **The hook cannot go there.** `evaluateExtraParams()` is the *last* +statement of `evaluateParams()` (`UIBean.java:905`), and that is where `TextField` sets `attributes.type` — +so at the `tagNames` block the control type is not yet resolved and every text field would look like `OTHER`. + +The hook therefore goes at the very end of `evaluateParams()`, after the `evaluateExtraParams()` call. The +`form` local is declared at method scope and is still in scope there (the tooltip block below it already +uses it). When the constant is on and a form was found: ``` form.getFieldValidators(translatedName) - → provider.constraintsFor(validators, HtmlControlType.from(type)) + → provider.constraintsFor(validators, getControlType()) → addParameter("constraints", map) ```
