This is an automated email from the ASF dual-hosted git repository. lukaszlenart pushed a commit to branch docs/html5-constraint-validation in repository https://gitbox.apache.org/repos/asf/struts-site.git
commit 0bda63ed416813bdfc45cc0df7f44e1c26fff963 Author: Lukasz Lenart <[email protected]> AuthorDate: Tue Aug 25 00:13:48 2026 +0200 docs: document html5 constraint validation, deprecate the JS validator Rewrites client-side-validation.md around the html5 theme's new HTML5 constraint-validation attributes (struts.ui.html5.constraints), including the never-false-reject rule, the full validator-to-attribute mapping, the trim="false"/caseSensitive="true" conditions on stringlength/regex, the never-change-the-type rule, data-msg-* hooks, the requiredLabel/required distinction, and the swappable HtmlConstraintProvider extension point. Deprecates the older generated-JavaScript client-side validator (xhtml/ css_xhtml themes, <s:form validate="true">) per WW-5694, removed in 8.0.0 per WW-5696: deletes pure-java-script-client-side-validation.md, repoints its inbound links (xhtml-theme.md, css-xhtml-theme.md, ajax-client-side-validation.md) to the deprecated section of the rewritten page, adds deprecation banners to client-validation-example.md and form-tag.md's validate attribute. Drops the deleted page's claim that client-side messages are not internationalized: ValidatorSupport.getMessage resolves through DelegatingValidatorContext and textProviderFactory, so they always were. Co-Authored-By: Claude Opus 5 <[email protected]> --- .../core-developers/ajax-client-side-validation.md | 4 +- source/core-developers/client-side-validation.md | 171 ++++++++++++++++----- .../core-developers/client-validation-example.md | 6 + .../pure-java-script-client-side-validation.md | 50 ------ source/tag-developers/css-xhtml-theme.md | 21 +-- source/tag-developers/form-tag.md | 7 + source/tag-developers/xhtml-theme.md | 11 +- 7 files changed, 168 insertions(+), 102 deletions(-) diff --git a/source/core-developers/ajax-client-side-validation.md b/source/core-developers/ajax-client-side-validation.md index b9e47ed69..45012487e 100644 --- a/source/core-developers/ajax-client-side-validation.md +++ b/source/core-developers/ajax-client-side-validation.md @@ -14,8 +14,8 @@ parent: ## Description -AJAX-based client side validation improves upon [Pure JavaScript Client Side Validation](pure-java-script-client-side-validation) -by using a combination of JavaScript, DOM manipulation, and remote server communication. Unlike the pure client side +AJAX-based client side validation improves upon [Pure JavaScript Client Side Validation](client-side-validation#pure-javascript-client-side-validation-deprecated) +(deprecated since Struts 7.4.0, removed in 8.0.0) by using a combination of JavaScript, DOM manipulation, and remote server communication. Unlike the pure client side implementation, AJAX-based validation communicates with the server. This means all your validation rules that worked when submitting a form will still work within the browser. diff --git a/source/core-developers/client-side-validation.md b/source/core-developers/client-side-validation.md index 20a8dabad..e281ba7ea 100644 --- a/source/core-developers/client-side-validation.md +++ b/source/core-developers/client-side-validation.md @@ -14,57 +14,156 @@ parent: ## Basics -The framework adds support for client-side validation on top of the standard validation framework. +Since Struts 7.4.0, the [html5 theme](../tag-developers/html5-theme) can derive HTML5 constraint-validation +attributes (`required`, `minlength`, `maxlength`, `pattern`, `min`, `max`) directly from a field's +server-side [validators](validation), so the browser rejects obviously-invalid input before the form is +even submitted. This replaces the older, generated-JavaScript validator used by the _xhtml theme_ and +_css_xhtml theme_, which is now deprecated — see [Pure JavaScript Client Side Validation +(deprecated)](#pure-javascript-client-side-validation-deprecated) below. -Client-side validation can be enabled on a per-form basis by specifying `validate="true"` in the _form_ tag. +There is also [AJAX Client Side Validation](ajax-client-side-validation), which runs the full server-side +validation stack (including visitor validators and `validate()`) over AJAX and is unaffected by any of this. -```jsp -<s:form name="test" action="javascriptValidation" validate="true"> - ... -</s:form> -``` +## HTML5 Constraint Validation -If a `name` for the form is not given, the action mapping name will be used as the form name. Otherwise, a correct -`action` and `namespace` attributes must be provided to the `<saf:form>` tag. +### Enabling it -## Referencing "submitProfile" in the "/user" namespace +HTML5 constraint validation is off by default. Turn it on with the `struts.ui.html5.constraints` constant: -```jsp -<s:form namespace="/user" action="submitProfile" validate="true"> - ... -</s:form> +```properties +struts.ui.html5.constraints=true +``` + +It only has an effect on fields rendered with the `html5` theme (see [Using the HTML5 +theme](../tag-developers/html5-theme#using-the-html5-theme)). There is no per-form opt-in attribute — +unlike the deprecated JavaScript validator, this feature does not use `<s:form validate="true">`. Once the +constant is on and a field's theme is `html5`, its validators are consulted automatically. + +> The constant defaults to `false` in 7.4.0 so existing `html5`-theme forms keep rendering unchanged. The +> default is expected to flip to `true` in Struts 8.0.0. + +### The governing rule: never false-reject + +The mapping is deliberately conservative. A constraint is emitted only when the browser cannot reject +input the server would have accepted. If the browser rejected something the server allows, the user would +be stuck with a form that will not submit and no explanation why. Being conservative simply costs a field +its client-side check — that's a harmless, quiet failure mode, so the mapping always chooses it over the +alternative. + +The clearest consequence of this rule: **Struts never sets or changes an input's `type`.** A field stays +whatever `type` the developer gave it. In particular: + +- Switching a field to `type="number"` would reject a value like `1234,50`, which the framework's + locale-aware numeric conversion happily accepts in a comma-decimal locale. +- The browsers' `email` and `url` input grammars don't match `EmailValidator` and `UrlValidator`. + +So `min`/`max` range constraints are only ever added to a control the developer *already* made numeric +(`type="number"` or `type="range"`) — Struts will never promote a plain text field into one just because +an `int` or `double` validator is attached to it. + +### Mapping table + +| Validator | Emits | Condition | +|---|---|---| +| `requiredstring` | `required` | on text-entry controls (`text`, `search`, `tel`, `password`, `email`, `url`) and `textarea` | +| `required` | `required` | only on `radio` and `file` | +| `stringlength` | `minlength` / `maxlength` | on text-entry or `textarea`, and only if the validator has `trim="false"`; each attribute is added only if actually configured | +| `regex` | `pattern` | on text-entry controls only, and only if `caseSensitive="true"`, `trim="false"`, and the regex is ECMAScript-safe (see below) | +| `int`, `short`, `long` | `min` / `max` | only when the control is already `type="number"` or `type="range"` | +| `double` | `min` / `max` | same as above; only inclusive bounds are emitted — exclusive bounds have no HTML equivalent and are omitted | +| `date` | — | nothing yet; temporal `min`/`max` is deferred to a future release | +| `email`, `url`, `creditcard` | — | never emitted | +| `fieldexpression`, `expression`, `conversion`, visitor validators | — | never emitted | +| any validator carrying a message | `data-msg-<validatorType>` | always added, including for validators that emit no constraint attribute at all | + +Two of these conditions are easy to miss and sharply limit how often `required` and `pattern` actually show up: + +**`required` is split across two validators, and they don't behave alike.** `requiredstring` fails on +null, empty, and (by default) blank values, so it is strictly stricter than the browser's `required` — safe +to emit on any text-entry control. Plain `required`, however, only fails on a null value, an empty array, +or an empty collection. That means an empty text input (which submits `""`, not nothing), a `select` with +an empty-valued option, and an **unticked checkbox** (`CheckboxInterceptor` substitutes the parameter +`"false"` for it) all pass server-side validation while a browser `required` attribute would block them. +Only `radio` and `file` controls omit their parameter entirely when left empty, so those are the only two +control types where plain `required` agrees with the server — which is why the table above emits `required` +for the `required` validator on those two types alone. + +**`pattern` needs `trim="false"`, which is not the default.** `RegexFieldValidator.trim` defaults to +`true`, so the server matches the field's *trimmed* value while an HTML `pattern` attribute matches the +*raw* one. A regex like `[a-z]+` would accept `"abc "` server-side while the browser blocks it. Because of +this, `pattern` is only ever emitted for validators explicitly configured with `trim="false"` — which most +existing `regex` validators are not. In practice, expect `pattern` to show up rarely until applications +start setting `trim="false"` deliberately for fields where it's safe. + +**ECMAScript-safe** means the regex uses only constructs that mean the same thing in Java's regex engine +and in the browser's: literals, `\d`/`\w` and their negations, character classes without POSIX or Unicode +property syntax, grouping, alternation, anchors, and bounded quantifiers. Notably, **`\s` and `\S` are +excluded** — Java's `\s` is ASCII-only by default while ECMAScript's `\s` covers the wider Unicode +whitespace set, so a pattern like `^\S+$` would accept a value containing a non-breaking space server-side +and reject it in the browser. Any regex using a construct outside this allowlist simply gets no `pattern` +attribute at all — it is never rejected loudly, it just quietly doesn't get a client-side check. + +### `data-msg-*` attributes + +Every validator carrying a message — even one that emits no HTML constraint attribute at all — adds a +`data-msg-<validatorType>` attribute (for example `data-msg-email`, `data-msg-regex`) holding the +validator's fully resolved, internationalized message. **Struts ships no JavaScript that reads these.** +They exist purely as a hook: an application can write its own script to read `data-msg-*` and show +whichever messages it wants, in whatever way it wants, including for validators (like `email` or +`creditcard`) that never get a native browser check. + +### `requiredLabel` is unrelated to the `required` attribute + +This is a common point of confusion: the `requiredLabel` tag attribute only controls whether a visual +marker (usually `*`) is drawn next to a field's label. It has no connection to the HTML `required` +attribute described above, and setting `requiredLabel="true"` does not make a field required in the +browser — the two are decided completely independently. + +### Extension point: `HtmlConstraintProvider` + +The mapping above is implemented by `StrutsHtmlConstraintProvider`, the default implementation of the +`HtmlConstraintProvider` interface, registered under the `struts.htmlConstraintProvider` constant: + +```properties +struts.htmlConstraintProvider=struts ``` -Technically, the form's action attribute can refer to a "path" that includes the namespace and action as a URI. -But, client-side validation **requires** that the action name and namespeact to be set separately. +An application that wants a less conservative mapping — for example, treating an `email` validator as +`type="email"`, or emitting `pattern` for case-insensitive regexes by rewriting them — can register its own +`HtmlConstraintProvider` implementation under this constant instead of the default. This is the escape +hatch for every limitation described above: the framework's own mapping stays deliberately conservative, +but nothing stops an application from replacing it with one that fits its own validators and locales. + +## Pure JavaScript Client Side Validation (deprecated) + +> **Deprecated since Struts 7.4.0 ([WW-5694](https://issues.apache.org/jira/browse/WW-5694)), removed in +> Struts 8.0.0 ([WW-5696](https://issues.apache.org/jira/browse/WW-5696)).** New applications should use +> the [html5 theme's constraint validation](#html5-constraint-validation) described above instead. -## Won't work with client-side validation! +The `<s:form validate="true">` attribute enables an older client-side validation mechanism, used by the +_xhtml theme_ and _css_xhtml theme_. It uses 100% client-side JavaScript, generated from the same +validation configuration used server-side, to try to reject bad input before the form is submitted: ```jsp -<s:form action="/user/submitProfile.action" validate="true"> +<s:form name="test" action="javascriptValidation" validate="true"> ... </s:form> - ``` -All the usual [validation configuration](validation) steps apply to client-side validation. Client-side validation -uses the same validation rules as server-side validation. If server-side validation doesn't work, then client-side -validation won't work either. +If a `name` for the form is not given, the action mapping name is used as the form name. Otherwise, a +correct `action` and `namespace` attribute must be provided to the `<s:form>` tag — client-side validation +requires the action name and namespace to be resolvable separately, so a form whose `action` is given as a +full URI (for example `<s:form action="/user/submitProfile.action" validate="true">`) will not get +client-side validation, even though the form still works. -## The left hand doesn't know ... - -> The required attribute on many _Struts Tags_ is not integrated with client-side validation! The tag attribute is used -> by certain themes (like xhtml) to put a visual marker (usually '*') next to the field. The tag doesn't know -> if the validation system actually "requires" the field or not. +Because the validation logic is repeated in generated JavaScript, only a subset of validators is +supported (`required`, `requiredstring`, `stringlength`, `regex`, `email`, `url`, `int`, `double`), it is +not available for visitor validators at all, and — being a separate implementation of each validator's +logic — some values the JavaScript accepts may still be rejected server-side, or vice versa. This is one of +the reasons it is being replaced: the html5 theme's constraint validation above is derived directly from +the real validators, rather than reimplementing them in JavaScript. ## Example -See [Client Validation example](client-validation-example) for a complete example of client-side validation. - -## Client Side Validation Types - -There are two styles of client side validation. - -|[Pure JavaScript Client Side Validation](pure-java-script-client-side-validation)|Used by the _xhtml theme_ and _css_xhtml theme_| -|-----------------------------------------------------|--------------------------------------------------| -|[AJAX Client Side Validation](ajax-client-side-validation)|Use to used by the _ajax theme_ | +See [Client Validation example](client-validation-example) for a complete, though now-deprecated, example +of the JavaScript-based client-side validation described above. diff --git a/source/core-developers/client-validation-example.md b/source/core-developers/client-validation-example.md index 751e08121..3e3d5573a 100644 --- a/source/core-developers/client-validation-example.md +++ b/source/core-developers/client-validation-example.md @@ -8,6 +8,12 @@ parent: # Client Validation Example +> **Deprecated since Struts 7.4.0 ([WW-5694](https://issues.apache.org/jira/browse/WW-5694)), removed in +> Struts 8.0.0 ([WW-5696](https://issues.apache.org/jira/browse/WW-5696)).** This example walks through the +> generated-JavaScript client-side validator (`<s:form validate="true">`) used by the _xhtml theme_ and +> _css_xhtml theme_. New applications should use the [html5 theme's constraint +> validation](client-side-validation#html5-constraint-validation) instead. + Let's create a Client-Side validation workflow, step by step. The `validate` attribute is set to `true`. > Note: Some themes do not support client-side validation. diff --git a/source/core-developers/pure-java-script-client-side-validation.md b/source/core-developers/pure-java-script-client-side-validation.md deleted file mode 100644 index 43fde3e84..000000000 --- a/source/core-developers/pure-java-script-client-side-validation.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -layout: default -title: Pure JavaScript Client Side Validation -parent: - title: Client Side Validation - url: client-side-validation ---- - -# Pure JavaScript Client Side Validation -{:.no_toc} - -* Will be replaced with the ToC, excluding a header -{:toc} - -## Description - -Pure JavaScript client side validation is the simplest but least feature-rich type of [Client Side Validation](client-side-validation). -This type of validation uses 100% client-side JavaScript code to try to validate the values entered by the user. -Because the validation logic is actually repeated in the JavaScript code, it is important to understand that -some values will be considered acceptable by the JavaScript code but will be marked as unacceptable by the server-side [Validation](validation). - -Only the following validators are supported: - -* required validator -* requiredstring validator -* stringlength validator -* regex validator -* email validator -* url validator -* int validator -* double validator - -> JavaScript client validation is not available for visitor validations. - -## Error reporting - -Because client side validation does not talk to the server, the theme (_xhtml theme_ or _css_xhtml theme_ ) is responsible -for properly manipulating the HTML DOM to display the error message inline. The JavaScript that is responsible for doing -this logic is `validation.js` and can be found in each theme. - -> Errors are reported using the default validation message, not the internationalized version that the server-side might -> be aware of. This is a known issue. You may want to try the [AJAX Client Side Validation](ajax-client-side-validation) -> for messages that are fully internationalized. - -## Additional Validator Support - -If you wish to add additional validator support beyond those listed, you may override the _xhtml theme_ template -`form-close-validate.ftl`. This file contains the JavaScript that tries to validate each user-entered value from within -the browser. The _css_xhtml theme_ extends the _xhtml theme_ and therefore doesn't have its own `form-close-validate.ftl` -template. diff --git a/source/tag-developers/css-xhtml-theme.md b/source/tag-developers/css-xhtml-theme.md index a6d3e73e0..44176e72e 100644 --- a/source/tag-developers/css-xhtml-theme.md +++ b/source/tag-developers/css-xhtml-theme.md @@ -14,8 +14,9 @@ The _css_xhtml theme_ provides all the basics that the [simple theme](simple-the [textfield](textfield-tag), [select](select-tag), etc) - Labels for each of the HTML [Struts Tags](struts-tags), placed according to the CSS stylesheet - [Validation](../core-developers/validation) and error reporting -- [Pure JavaScript Client Side Validation](../core-developers/pure-java-script-client-side-validation) using 100% - JavaScript on the browser +- [Pure JavaScript Client Side Validation](../core-developers/client-side-validation#pure-javascript-client-side-validation-deprecated) + using 100% JavaScript on the browser — **deprecated since Struts 7.4.0, removed in 8.0.0**; use the + [html5 theme](html5-theme) instead ## Wrapping the Simple Theme @@ -69,15 +70,15 @@ The head includes a style sheet. The contents of **styles.css** are: ### Form template The css_xhtml [form](form-tag) template is almost exactly like the _xhtml form template_ , including support for -[Pure JavaScript Client Side Validation](../core-developers/pure-java-script-client-side-validation). The difference -is that instead of printing out an opening and closing `<table>` element, there are no elements. Instead, the CSS rules -for the individual HTML tags are assumed to handle all display logic. However, as noted, client-side validation is still -supported. +[Pure JavaScript Client Side Validation](../core-developers/client-side-validation#pure-javascript-client-side-validation-deprecated) +(deprecated since Struts 7.4.0, removed in 8.0.0). The difference is that instead of printing out an opening and closing +`<table>` element, there are no elements. Instead, the CSS rules for the individual HTML tags are assumed to handle all +display logic. However, as noted, client-side validation is still supported. ### css_xhtml form template The css_xhtml [form](form-tag) template is almost exactly like the _xhtml form template_ , including support for -[Pure JavaScript Client Side Validation](../core-developers/pure-java-script-client-side-validation). The only -difference is that instead of printing out an opening and closing `<table>` element, there are no elements. Instead, -the CSS rules for the individual HTML tags are assumed to handle all display logic. However, as noted, client side -validation is still supported. +[Pure JavaScript Client Side Validation](../core-developers/client-side-validation#pure-javascript-client-side-validation-deprecated) +(deprecated since Struts 7.4.0, removed in 8.0.0). The only difference is that instead of printing out an opening and +closing `<table>` element, there are no elements. Instead, the CSS rules for the individual HTML tags are assumed to +handle all display logic. However, as noted, client side validation is still supported. diff --git a/source/tag-developers/form-tag.md b/source/tag-developers/form-tag.md index 52684722e..c516e3730 100644 --- a/source/tag-developers/form-tag.md +++ b/source/tag-developers/form-tag.md @@ -41,3 +41,10 @@ There are two flavours [Client Side Validation](../core-developers/client-side-v are using (xhtml, ajax, etc). If you are using the [xhtml theme](xhtml-theme) or [css_xhtml theme](css-xhtml-theme), pure client side validation will be used. Read the [Client Side Validation](../core-developers/client-side-validation) docs for more information. + +> **`validate` is deprecated since Struts 7.4.0 and will be removed in 8.0.0** +> ([WW-5694](https://issues.apache.org/jira/browse/WW-5694), +> [WW-5696](https://issues.apache.org/jira/browse/WW-5696)). It only controls the older, generated-JavaScript +> client-side validator used by the xhtml and css_xhtml themes. It has no effect on the [html5 theme's constraint +> validation](../core-developers/client-side-validation#html5-constraint-validation), which applications should +> use instead. diff --git a/source/tag-developers/xhtml-theme.md b/source/tag-developers/xhtml-theme.md index feb021489..abed1e85f 100644 --- a/source/tag-developers/xhtml-theme.md +++ b/source/tag-developers/xhtml-theme.md @@ -19,8 +19,9 @@ The xhtml provides all the basics that the [simple theme](simple-theme) provides - Labels for each of the HTML [Struts Tags](struts-tags) on the left hand side (or top, depending on the `labelposition` attribute) - [Validation](../core-developers/validation) and error reporting -- [Pure JavaScript Client Side Validation](../core-developers/pure-java-script-client-side-validation) using - 100% JavaScript on the browser +- [Pure JavaScript Client Side Validation](../core-developers/client-side-validation#pure-javascript-client-side-validation-deprecated) + using 100% JavaScript on the browser — **deprecated since Struts 7.4.0, removed in 8.0.0**; use the + [html5 theme](html5-theme) instead ## Wrapping the Simple Theme @@ -94,7 +95,8 @@ The head template imports a style sheet. The contents of **styles.css** are: The xhtml form template sets up the wrapping table around all the other form elements. In addition to creating this wrapping table, the opening and closing templates also, if the `validate` parameter is set to true, enable -[Pure JavaScript Client Side Validation](../core-developers/pure-java-script-client-side-validation). +[Pure JavaScript Client Side Validation](../core-developers/client-side-validation#pure-javascript-client-side-validation-deprecated) +(deprecated since Struts 7.4.0, removed in 8.0.0). {% highlight freemarker %} {% remote_file_content https://raw.githubusercontent.com/apache/struts/main/core/src/main/resources/template/xhtml/form.ftl %} @@ -110,7 +112,8 @@ The closing template, `form-close.ftl`: The xhtml form template sets up the wrapping table around all the other [xhtml theme](xhtml-theme) form elements. In addition to creating this wrapping table, the opening and closing templates also, if the `validate` parameter is set -to `true`, enable [Pure JavaScript Client Side Validation](../core-developers/pure-java-script-client-side-validation.htmk). +to `true`, enable [Pure JavaScript Client Side Validation](../core-developers/client-side-validation#pure-javascript-client-side-validation-deprecated) +(deprecated since Struts 7.4.0, removed in 8.0.0). See the **form.ftl** contents:
