Validator skipped when input is removed in client

2019-01-15 03:28发布

问题:

I have a page with an input text component marked as required="true" and having a custom Validator in server side.

Now as a client, I submit the page without the HTML element rendered by that component (this can be easily achieved by removing the element from the DOM tree using browser's builtin DOM element inspector). The form is successfully submitted, without the server side validation of this required component.

Is this as per JSF specification? Is there a way to specify that the validators in the page are to be executed even if the posted page do not contain them?

回答1:

This is as per the specification. Here's an extract of relevance from UIInput#validate() javadoc:

Retrieve the submitted value with getSubmittedValue(). If this returns null, exit without further processing. (This indicates that no value was submitted for this component.)

An empty input will send an empty string, not null. A complete absence of the input will send null, not empty string.

Whether that is harmful or not depends on the business logic. A decently designed model (business logic and/or data model) which doesn't consider null as expected case would cause a null pointer exception elsewhere, or a SQL constraint violation (NOT NULL), which will usually end up in a HTTP 500 error response. But if the model actually considers null as an expected case, then it's likely a fault in the model. The view (the JSF page), intented to merely present the model, can then do little against it.

If the business logic or data model can really not be altered to consider null as an exceptional case (i.e. never assume/accept the given value as null), and you happen to use JPA, then your best bet is to add a @NotNull on the property. Whilst JSF will bypass validation on it, JPA will still validate it, causing still an exception and a HTTP 500 error. I'd in this case only wonder why the DB column doesn't have a NOT NULL constraint in first place. Alternatively, do class level validation.

Noted should be that MyFaces logs a warning like below on this:

Mar 16, 2016 8:55:52 AM org.apache.myfaces.shared.renderkit.html.HtmlRendererUtils decodeUIInput
WARNING: There should always be a submitted value for an input if it is rendered, its form is submitted, and it was not originally rendered disabled or read-only. You cannot submit a form after disabling an input element via javascript. Consider setting read-only to true instead or resetting the disabled value back to false prior to form submission.
Component : {Component-Path : [Class: javax.faces.component.UIViewRoot,ViewId: /test.xhtml][Class: javax.faces.component.html.HtmlBody,Id: j_id_5][Class: javax.faces.component.html.HtmlForm,Id: j_id_6][Class: javax.faces.component.html.HtmlInputText,Id: j_id_7] Location: /test.xhtml at line 22 and column 33}