lukaszlenart opened a new pull request, #1865: URL: https://github.com/apache/struts/pull/1865
Adds HTML5 constraint validation to the `html5` theme, and deprecates the generated-JavaScript client-side validator it replaces. Fixes [WW-5695](https://issues.apache.org/jira/browse/WW-5695) Fixes [WW-5694](https://issues.apache.org/jira/browse/WW-5694) Supersedes [WW-2975](https://issues.apache.org/jira/browse/WW-2975) (closed Won't Fix), open since 2009. Removal of the JavaScript validator is tracked separately as [WW-5696](https://issues.apache.org/jira/browse/WW-5696) and is **not** in this PR. ## Why `xhtml/form-close-validate.ftl` builds its `validateForm_<id>()` function from the form's `tagNames` list, which is populated only when a UI tag finds the form via `findAncestor(Form.class)`. Any input reaching the markup another way — raw HTML, a custom tag, an included fragment — is silently unvalidated. That is WW-2975, and it still reproduced on `main`. Rather than patch that list, this replaces the mechanism. Constraints now ride on each `<input>`, so there is no central field list for a field to be missing from — the root cause disappears instead of being worked around. ## The governing rule: never false-reject A constraint is emitted **only** when the browser cannot reject input the server would have accepted. A browser rejecting what the server allows leaves the user with a form that will not submit and no explanation. Being conservative merely costs a field its client-side check, which is harmless. The main consequence: **Struts never sets or changes an input's `type`.** Promoting a field to `type="number"` would reject `1234,50`, which locale-aware conversion accepts in a comma-decimal locale, and the browsers' `email`/`url` grammars differ from `EmailValidator`/`URLValidator`. ## What is emitted | Validator | Emits | Condition | |---|---|---| | `requiredstring` | `required` | text-entry controls and `textarea` | | `required` | `required` | only `radio` and `file` | | `stringlength` | `minlength` / `maxlength` | text-entry or `textarea`, and `trim="false"` | | `regex` | `pattern` | text-entry, `caseSensitive="true"`, `trim="false"`, ECMAScript-safe, not email/creditcard | | `int`, `short`, `long`, `double` | `min` / `max` | only when the control is already `type="number"`/`range`; `min` only when integral | | `date` | — | temporal formatting deferred | | `email`, `url`, `creditcard` | — | never | | any validator with a message | `data-msg-<type>` | always, including those emitting no constraint | Struts ships **no JavaScript** consuming `data-msg-*`; they carry the resolved i18n message for an application's own script. Three conditions are worth knowing because they limit reach: - `required` is split because `RequiredFieldValidator` only fails on null/empty-array/empty-collection. `CheckboxInterceptor` substitutes `"false"` for an unticked box, so the server accepts what a browser `required` would block. Only `radio` and `file` omit the parameter entirely when empty. - `minlength`/`maxlength` and `pattern` both need `trim="false"`, which is **not** the default — the server measures/matches the trimmed value while the attribute constrains the raw one. Expect both to be uncommon until applications opt in. - `\s`/`\S` are excluded from the ECMAScript-safe allowlist: Java's is ASCII-only by default while ECMAScript's is the wider Unicode set, so `^\S+$` would accept a value containing NBSP server-side and reject it in the browser. ## Compatibility Off by default (`struts.ui.html5.constraints=false`), so nothing renders differently on upgrade — the `html5` theme shipped in 7.2.0 and existing forms are untouched. The deprecation is annotations and documentation only; all four `validateForm_` golden files are byte-identical. The mapping policy is a swappable bean (`HtmlConstraintProvider`, under `struts.htmlConstraintProvider`) for applications wanting a less conservative mapping. ## Testing Full core suite: **3257 tests, 0 failures.** `mvn apache-rat:check` clean. The plugin modules that consume `UIBean` (`javatemplates`, `velocity`) verified green with `-am`. Several tests exist specifically to be able to fail: the hook-ordering test was confirmed to fail when the hook is moved, the memoisation test when the cache is disabled, and the byte-exact disabled-path test when the template regresses — the shared golden-file harness normalises whitespace away, so it cannot catch that class of defect on its own. ## Known follow-ups - The `trim` guard over-restricts `minlength`: browser-reject implies server-reject there, so it could safely be emitted even when trimming. Widening it is a follow-up. - Temporal `min`/`max` needs per-control ISO formatting. - The `try/catch` guarding derivation has no regression test yet. Documentation is a companion change in `struts-site`. 🤖 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]
