- 

Available since OmniFaces 2.0

<o:viewParamValidationFailed> allows the developer to handle a view parameter validation failure with either a redirect or an HTTP error status, optionally with respectively a flash message or HTTP error message. This tag can be placed inside <f:metadata> or <f|o:viewParam>. When placed in <f|o:viewParam>, it will be applied when the particular view parameter has a validation error as per UIInput.isValid(). When placed in <f:metadata>, and no one view parameter has already handled the validation error via its own <o:viewParamValidationFailed>, it will be applied when there's a general validation error as per FacesContext.isValidationFailed().

When the sendRedirect attribute is set, a call to Faces.redirect(String, Object...) is made internally to send the redirect. So, the same rules as to scheme and leading slash apply here. When the sendError attribute is set, a call to Faces.responseSendError(int, String) is made internally to send the error. You can therefore customize HTTP error pages via <error-page> entries in web.xml. Otherwise the server-default one will be displayed instead.

<f:viewParam required="true"> fail

As a precaution; be aware that <f:viewParam required="true"> has a design error in current Mojarra and MyFaces releases (as of now, Mojarra 2.2.7 and MyFaces 2.2.4). When the parameter is not specified in the query string, it is retrieved as null, which causes an internal isRequired() check to be performed instead of delegating the check to the standard UIInput implementation. This has the consequence that PreValidateEvent and PostValidateEvent listeners are never invoked, which the <o:viewParamValidationFailed> is actually relying on. This is fixed in <o:viewParam>.

Examples

In the example below the client will be presented an HTTP 400 error when at least one view param is absent.

<f:metadata>
    <o:viewParam name="foo" required="true" />
    <o:viewParam name="bar" required="true" />
    <o:viewParamValidationFailed sendError="400" />
</f:metadata>

In the example below the client will be redirected to "login.xhtml" when the "foo" parameter is absent, regardless of the "bar" parameter. When the "foo" parameter is present, but the "bar" parameter is absent, nothing new will happen. The process will proceed "as usual". I.e. the validation error will end up as a faces message in the current view the usual way.

<f:metadata>
    <o:viewParam name="foo" required="true">
        <o:viewParamValidationFailed sendRedirect="login.xhtml" />
    </o:viewParam>
    <o:viewParam name="bar" required="true" />
</f:metadata>

In the example below the client will be presented an HTTP 401 error when the "foo" parameter is absent, regardless of the "bar" or "baz" parameters. When the "foo" parameter is present, but either the "bar" or "baz" parameter is absent, the client will be redirected to "search.xhtml".

<f:metadata>
    <o:viewParam name="foo" required="true">
        <o:viewParamValidationFailed sendError="401" />
    </o:viewParam>
    <o:viewParam name="bar" required="true" />
    <o:viewParam name="baz" required="true" />
    <o:viewParamValidationFailed sendRedirect="search.xhtml" />
</f:metadata>

In a nutshell: when there are multiple <o:viewParamValidationFailed> tags, they will be applied in the same order as they are declared in the view. So, with the example above, the one nested in <f|o:viewParam> takes precedence over the one nested in <f:metadata>.

Messaging

By default, the first occurring faces message on the parent component will be copied, or when there is none then the first occurring global faces message will be copied. When sendRedirect is used, it will be set as a global flash error message. When sendError is used, it will be set as HTTP status message.

You can override this message by explicitly specifying the message attribute. This is applicable for both sendRedirect and sendError.

<o:viewParamValidationFailed sendRedirect="search.xhtml" message="You need to perform a search." />
...
<o:viewParamValidationFailed sendError="401" message="Authentication failed. You need to login." />

Note, although all of above examples use required="true", this does not mean that you can only use <o:viewParamValidationFailed> in combination with required="true" validation. You can use it in combination with any kind of conversion/validation on <f|o:viewParam>, even bean validation.

Design notes

You can technically nest multiple <o:viewParamValidationFailed> inside the same parent, but this is not the documented approach and only the first one would be used.

You can not change the HTTP status code of a redirect. This is not a Faces limitation, but an HTTP limitation. The status code of a redirect will always end up as the one of the redirected response. If you intend to "redirect" with a different HTTP status code, then you should be using sendError instead and specify the desired page as <error-page> in web.xml.

Demo

This page has 6 view parameters: foo,bar, baz, faz, boo and foz. All with a jakarta.faces.Long converter, just for simplicity. You can of course use your own converters and validators, e.g. required="true", <f:validateLongRange>, etcetera. In case conversion (or validation) fails, the associated <o:viewParamValidationFailed> logic will be executed.

The first four view parameters have each their own <o:viewParamValidationFailed>, demonstrating the following cases:

The latter two view parameters which doesn't have their own <o:viewParamValidationFailed> and are both making use of the global one sending a 400. The message is conditionally set based on whether it was the foz parameter which failed.

Demo source code
<f:metadata>
    <f:viewParam name="foo" converter="jakarta.faces.Long">
        <o:viewParamValidationFailed sendError="400" />
    </f:viewParam>
    <f:viewParam name="bar" converter="jakarta.faces.Long">
        <o:viewParamValidationFailed sendError="400" message="Invalid bar!"/>
    </f:viewParam>
    <f:viewParam name="baz" converter="jakarta.faces.Long">
        <o:viewParamValidationFailed sendRedirect="whatsnew" />
    </f:viewParam>
    <f:viewParam name="faz" converter="jakarta.faces.Long">
        <o:viewParamValidationFailed sendRedirect="whatsnew" message="Invalid faz!" />
    </f:viewParam>
    <f:viewParam name="boo" converter="jakarta.faces.Long" />
    <f:viewParam name="foz" converter="jakarta.faces.Long" />
    <o:viewParamValidationFailed sendError="400" message="#{foz.valid ? null : 'Invalid foz!'}" />
</f:metadata>

<p>
    This page has 6 view parameters: <code>foo</code>,<code>bar</code>, <code>baz</code>, <code>faz</code>, 
    <code>boo</code> and <code>foz</code>. All with a <code>jakarta.faces.Long</code> converter, just for simplicity.
    You can of course use your own converters and validators, e.g. <code>required="true"</code>, 
    <code>&lt;f:validateLongRange&gt;</code>, etcetera. In case conversion (or validation) fails, the associated
    <code>&lt;o:viewParamValidationFailed&gt;</code> logic will be executed.
</p>
<p>
    The first four view parameters have each their own <code>&lt;o:viewParamValidationFailed&gt;</code>, 
    demonstrating the following cases:
</p>
<ul>
    <li><a href="?foo=abc">Sending a HTTP 400 error with default validation message.</a></li>
    <li><a href="?bar=abc">Sending a HTTP 400 error with a custom message.</a></li>
    <li><a href="?baz=abc">Sending a redirect to <code>/whatsnew</code> with default validation message (via flash).</a></li>
    <li><a href="?faz=abc">Sending a redirect to <code>/whatsnew</code> with a custom message (via flash).</a></li>
</ul>
<p>
    The latter two view parameters which doesn't have their own <code>&lt;o:viewParamValidationFailed&gt;</code>
    and are both making use of the global one sending a 400. The message is conditionally set based on whether it
    was the <code>foz</code> parameter which failed.
</p>
<ul>
    <li><a href="?boo=abc">Send a HTTP 400 error with default validation message.</a></li>
    <li><a href="?foz=abc">Send a HTTP 400 error with a custom message.</a></li>
</ul>