4
votes

Is it possible to perform some actions (some cleanup) if jsf validation errors occur?
Fields are validated with tags in xhtml, for example 'required="true"', 'f:validateRegex pattern="\d*"', 'f:validator validatorId="someValidator"'.
I need to set some property field of managed bean to null (when there are any failures on the page). But if validation fails, then JSF goes to Render Response Phase and managed bean method is not invoked. Listener (using f:actionListener tag) also is not invoked in that case.

Now I'm thinking about to replace xhtml validation by validation using bean annotations like @AssertTrue, @Size, etc. Then in some of this validating methods it would be possible to make a cleanup:

@ManagedBean
class SomeBean {
...
    @AssertTrue
    public void isClenup() {
        cleanup();
    }
...
}

But it seems not a good solution to me.
Also I noticed that several methods annotated with @AssertTrue are called in undefined order. Therefore switching from xhtml validation to bean annotations validation is getting not so easy.
Is it possible to define some order of calling methods annotated with @AssertTrue?

2

2 Answers

4
votes

In fact I have quite ordinary task: there is a page with search functionality.
On search success with no errors the result should be shown, but if validation errors occur (during next search), then previous result should not be shown (but it was visible and that was a problem).

My plan was as follows: to check for validation failures in initialize() method using facesContext.isValidationFailed() and if it is true, then to hide (delete) previous search results:

public void initialize() {
    FacesContext context = FacesContext.getCurrentInstance();
    boolean validationFailed = context.isValidationFailed();
    if(validationFailed) {
        clearPreviousSearchResult();
    }
}

But then I found out that validation using bean annotations (like @AssertTrue) does not set facesContext.validationFailed();! I.e. after this

@AssertTrue(message = "Some error message")
public boolean isValidateSomeField() {
    return validate(getSomeFieldValue());
}

you get context.isValidationFailed() == false when fails occur (though I expected true)
(xhtml validation or validator or f:validator do set facesContext.validationFailed() as expected)

Therefore it is necessary to set context failed manually:

@AssertTrue(message = "Some error message")
public boolean isValidateSomeField() {
    if(!validate(getSomeFieldValue())) {
        FacesContext.getCurrentInstance().validationFailed();
        return false;
    }
    return true;
}

But due to How to check in after phase of Validations phase if validation has failed? I realized that the problem can be resolved much more easier! Just to wrap with couple of lines:

<h:panelGroup rendered="#{!facesContext.validationFailed}">
    ...block not to show if validation errors occur...
</h:panelGroup>

And no need to use annotations bean validation and some initialize() method!

3
votes

If a validation exception is thrown during the JSF validation phase then none of the submitted form values will be applied to the model. Also none of the invoked events that would otherwise execute during the Invoke Application JSF phase will be called. You do notice however that Render will still occur, and any components that need to be rendered or updated will still do so.

In theory this should be sufficient for rolling back most any user submissions if any of those submissions were invalid, however there are a few edge cases where additional cleanup will need to occur. I urge you however to closely evaluate the design decisions that led you to this need in the first place, as it is possible that perhaps there is a better way to meet your business requirements without having to resort to this.

With that being said, I would perform a Pre Render event that will execute on every postback and check for certain validations and perform necessary business and presentation logic.

<f:event listener="#{managedBean.initialize()}" type="preRenderView" />