[ 
https://issues.apache.org/jira/browse/WW-5695?focusedWorklogId=1037684&page=com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel#worklog-1037684
 ]

ASF GitHub Bot logged work on WW-5695:
--------------------------------------

                Author: ASF GitHub Bot
            Created on: 25/Aug/26 06:04
            Start Date: 25/Aug/26 06:04
    Worklog Time Spent: 10m 
      Work Description: sonarqubecloud[bot] commented on PR #1865:
URL: https://github.com/apache/struts/pull/1865#issuecomment-5406244298

   ## [![Quality Gate 
Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png
 'Quality Gate 
Passed')](https://sonarcloud.io/dashboard?id=apache_struts&pullRequest=1865) 
**Quality Gate passed**  
   Issues  
   
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png
 '') [2 New 
issues](https://sonarcloud.io/project/issues?id=apache_struts&pullRequest=1865&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)
  
   
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png
 '') [0 Accepted 
issues](https://sonarcloud.io/project/issues?id=apache_struts&pullRequest=1865&issueStatuses=ACCEPTED)
   
   Measures  
   
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png
 '') [0 Security 
Hotspots](https://sonarcloud.io/project/security_hotspots?id=apache_struts&pullRequest=1865&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)
  
   
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png
 '') [90.1% Coverage on New 
Code](https://sonarcloud.io/component_measures?id=apache_struts&pullRequest=1865&metric=new_coverage&view=list)
  
   
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png
 '') [0.0% Duplication on New 
Code](https://sonarcloud.io/component_measures?id=apache_struts&pullRequest=1865&metric=new_duplicated_lines_density&view=list)
  
     
   <!

Issue Time Tracking
-------------------

    Worklog Id:     (was: 1037684)
    Time Spent: 0.5h  (was: 20m)

> Derive HTML5 constraint attributes from validators in the html5 theme
> ---------------------------------------------------------------------
>
>                 Key: WW-5695
>                 URL: https://issues.apache.org/jira/browse/WW-5695
>             Project: Struts 2
>          Issue Type: New Feature
>            Reporter: Lukasz Lenart
>            Priority: Major
>             Fix For: 7.4.0
>
>          Time Spent: 0.5h
>  Remaining Estimate: 0h
>
> h2. Goal
> Let the {{html5}} theme emit native HTML5 constraint attributes 
> ({{required}}, {{minlength}}, {{maxlength}}, {{pattern}}, {{min}}, {{max}}) 
> derived from the action's validators, as the successor to the JavaScript 
> client-side validator deprecated in WW-5694.
> Because constraints ride on each individual input rather than on a generated 
> per-form function, this also dissolves the root cause of WW-2975 instead of 
> patching it — there is no central field list for a field to be missing from.
> h2. The governing rule: never false-reject
> A constraint is emitted only when the browser cannot reject something the 
> server would accept. This rules out more than it first appears:
> {{min}} and {{max}} are inert on {{type="text"}} — they only apply to 
> {{number}}, {{range}} and the temporal types. Honouring an int or double 
> validator therefore means switching the input to {{type="number"}}, and that 
> _is_ a false rejection: a browser {{type="number"}} refuses {{1234,50}}, 
> which the framework's locale-aware conversion accepts in a comma-decimal 
> locale. The same argument rules out {{type="email"}} and {{type="url"}}, 
> whose browser regexes diverge from {{EmailValidator}} and {{URLValidator}} — 
> see WW-4395, still open, for the email side of that divergence.
> Hence the rule: _Struts never sets or changes an input's type. It only adds 
> constraints that are safe for whatever type is already there._ A developer 
> who writes {{type="number"}} has accepted that widget's semantics, so {{min}} 
> and {{max}} become pure additions.
> h2. Mapping
> || Validator || Emits || Condition ||
> | required | required | always |
> | requiredstring | required | always; the server is stricter on 
> whitespace-only input, which is safe |
> | stringlength | minlength / maxlength | only when {{trim="false"}} — the 
> server measures the trimmed value, so a maxlength derived from a trimming 
> validator would stop the user typing input the server would accept |
> | regex | pattern | only when {{caseSensitive="true"}} and the regex is 
> ECMAScript-safe |
> | int, short, long | min / max | only when the control is already numeric |
> | double | min / max | only when the control is already numeric |
> | date | min / max | only when the control is already temporal |
> | email, url | nothing | browser regexes diverge from the framework's |
> | creditcard, fieldexpression, expression, conversion, visitor | nothing | no 
> safe mapping |
> {{RegexFieldValidator}} uses {{matcher.matches()}}, so it is fully anchored 
> and matches HTML5 {{pattern}} semantics. The divergence is syntactic, not 
> positional — Java-only constructs such as POSIX classes, possessive 
> quantifiers and {{\\A}} / {{\\z}} are the hazard, and 
> {{caseSensitive="false"}} has no {{pattern}} equivalent because HTML allows 
> no regex flags.
> ECMAScript-safety detection must be an _allowlist_, not a denylist: a 
> denylist violates the rule the first time it misses a construct. Allow 
> literals, {{\\d}} {{\\w}} {{\\s}} and their negations, character classes 
> without POSIX or Unicode property syntax, grouping, alternation, anchors and 
> bounded quantifiers; emit no {{pattern}} for anything else. This is 
> deliberately strict and is the piece most likely to need tuning after real 
> use.
> h2. Design
> * New constant {{struts.ui.html5.constraints}}, default {{false}} in 7.4.0. 
> The {{html5}} theme shipped in 7.2.0, so emitting {{required}} on upgrade 
> would start blocking submits on forms that render unchanged today. The 
> default flips to {{true}} in 8.0.0.
> * New enum {{HtmlControlType}} — the provider's real question is which 
> constraint attributes are legal on a control, not what string is in the type 
> attribute. It models the control rather than the attribute, because textarea 
> and select have no type attribute yet do accept {{required}}. Members cover 
> the HTML5 input types plus TEXTAREA, SELECT and OTHER, with predicates 
> {{supportsPattern()}}, {{supportsLength()}} and {{supportsRange()}}. Its 
> {{from(String)}} factory must never throw: the type attribute is 
> OGNL-evaluated, so at runtime it can be any string, and unknown values 
> normalise to OTHER, which supports nothing — the conservative default falls 
> out for free.
> * New interface {{HtmlConstraintProvider}} with default implementation 
> {{StrutsHtmlConstraintProvider}}, taking the field's validators and an 
> {{HtmlControlType}} and returning a map of attribute name to value. 
> Registered once in {{struts-beans.xml}} following the {{UrlRenderer}} model — 
> registering a bean under two types builds two instances. Because the default 
> policy is deliberately restrictive, the swappable bean is how applications 
> wanting best-effort mapping get served.
> * {{UIBean.evaluateParams}} already resolves the {{Form}} ancestor to 
> populate {{tagNames}}; that is the hook. Gate the computation on the constant 
> so the cost is zero when off.
> * New {{Form.getFieldValidators(String)}} that resolves the action's 
> validator list once and memoises it on the form's attributes, then filters 
> per call. The existing {{getValidators(String)}} re-runs the action-mapping 
> lookup on every call, so a twenty-field form would do twenty full lookups.
> * New {{html5/constraints.ftl}}, included from {{common-attributes.ftl}} so 
> every html5 input picks it up without per-template edits.
> h2. Messages
> The provider returns the full attribute set, not only constraints. Validator 
> messages ride the same map as {{data-msg-}} entries keyed by validator type — 
> {{data-msg-required}}, {{data-msg-stringlength}} — resolved via 
> {{validator.getMessage(action)}}, which goes through 
> {{DelegatingValidatorContext}} and {{textProviderFactory}} and is therefore 
> properly i18n'd.
> A message is emitted for every validator that has one, _including_ those 
> producing no constraint. An email validator therefore contributes 
> {{data-msg-email}} and nothing else, which is exactly where an application 
> most needs it. Struts ships nothing that consumes these attributes — no 
> JavaScript.
> h2. Do not conflate requiredLabel
> {{requiredLabel}} keeps meaning "draw an asterisk next to the label". It must 
> never produce a {{required}} attribute — only a {{required}} validator does. 
> This is the most likely regression in this work and needs an explicit test.
> h2. Testing
> The negative cases carry the weight, because they are what protects the rule: 
> {{stringlength trim="true"}} emits no length constraints; {{regex 
> caseSensitive="false"}} emits no pattern; a Java-only regex emits no pattern; 
> int and double on a text control emit no range; email and url never set or 
> change the type; {{HtmlControlType.from}} never throws on null or unknown 
> input.
> Note the harness trap: a form-validation tag test needs {{initDispatcher}} 
> with {{TestConfigurationProvider}} _and_ {{createMocks()}} in setUp, plus a 
> {{prepareMockInvocation()}} EasyMock helper. Without them 
> {{evaluateClientSideJsEnablement}} finds no {{ValidationInterceptor}}, 
> {{performValidation}} stays false, and no validation function is emitted at 
> all — so the test passes or fails for entirely the wrong reason.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to