best approach to do jsf form validation - jsf

If I have many input controls in a form (There are separate validators for each of these input controls - like required,length and so on ) , there is a command button which submits the form and calls an action method. The requirement is - though the input control values are , say , individually okay - the combination of these values should be okay to process them together after the form submission - Where do i place the code to validate them together?
1) Can i add a custom validator for the command button and validate the combination together? like validate(FacesContext arg0, UIComponent arg1, Object value) but even then I will not have values of the other input controls except for the command button's/component's value right ?
2) can i do the validation of the combination in the action method and add validation messages using FacesMessage ?
or do you suggest any other approach?
Thanks for your time.

Point 2 is already answered by Bozho. Just use FacesContext#addMessage(). A null client ID will let it land in <h:messages globalOnly="true">. A fixed client ID like formId:inputId will let it land in <h:message for="inputId">.
Point 1 is doable, you can grab the other components inside the validator method using UIViewRoot#findComponent():
UIInput otherInput = (UIInput) context.getViewRoot().findComponent("formId:otherInputId");
String value = (String) otherInput.getValue();
You however need to place f:validator in the last UIInput component. Placing it in an UICommand component (like the button) won't work.
True, hardcoding the client ID's is nasty, but that's the payoff of a bit inflexible validation mechanism in JSF.

I've just landed on your post after having the same question.
Articles I have read so far identify that there are four types of validation for the following purposes:
Built into the Components (subscribe to individual fields; required=true, LengthValidator, etc)
'Application Validation' added to the Action in the Backing Bean (Business Logic)
Custom Validators (subscribe to individual fields)
Method in the Backing Bean used as a Custom Validator (subscribe to individual fields).
With reference to Validators: The validation mechanism in JSF was designed to validate a single component. (See S/O Question here)
In the case where you want to validate a whole form as a logical grouping of fields, it appears with standard JSF/Apache MyFaces that the most appropriate to do it is as Application Validation, as the set of individual fields take on a collective business meaning at this point.
BalusC has come up with a way of shoehorning form validation into a single validator attached to the last form item (again, see S/O Question here and another worked example on his website here) however it isn't necessarily extensible/reusable, as the references to the ID's of the form have to be hardcoded as you can't append to the validate() method's signature. You'll get away with it if you're only using the form once, but if it pops up a few times or if you generate your ID's programmatically, you're stuck.
The JSF implementation portion of Seam has a <s:validateForm /> control which can take the IDs of fields elsewhere in your form as parameters. Unfortunately, it doesn't appear that any of the MyFaces/Mojara/Sun JSF implementations have an equivalent as it isn't part of the standard.

I've successfully used the 2nd approach:
FacesMessage facesMessage =
new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, msg);
FacesContext.getCurrentInstance().addMessage(null, facesMessage);

Related

Can JSF be configured to not invoke Entity setter unless the field actually changed?

When a JSF form field is wired into an entity bean field (which is mapped to a DB field), each setter in the entity bean is called regardless of whether the user changed the form field value in the front end, i.e. the setters on unchanged fields are invoked the same as those that have changed but their new value is the same as the old value.
My question is simple: Is there a way to configure JSF to only call the setters mapped to the fields that have changed in the front end? The reason for this is that I have a requirement by which I have to detect deltas on every persist and log them, more about which can be read in this question.
Maybe I didn't understand you clearly, but why are you mapping directly your entity beans to a JSF view ?! IMHO it would be better if you add managed beans between your JSF pages and the entities in order to better separate your business logic from data access.
Any way, I think the easiest solution to impelement for that case is by making use of Value Change Events which are invoked "normally" after the Process Validations phase (unless you make use of the immediate attribute).
The good news about Value Change Events (regarding your example) is they are invoked ONLY after you force form submit using JavaScript or Command components AND the new value is different from the old value.
So, as an example on how to use value change listeners, you can add valueChangeListner attribute to each of your JSF tags like following:
<h:inputText id="input" value="#{someBean.someValue}"
valueChangeListener="#{someBean.valueChanged} />
Then, implement your valueChanged() method to look something like:
public void valueChanged(ValueChangeEvent event) {
// You can use event.getOldValue() and event.getNewValue() to get the old or the new value
}
Using the above implementation, may help you to separate your logging code (it will be included in the listeners) from your managed properties setters.
NB: Value Change Listeners may also be implemetend otherwise using the f:valueChangeListener Tag, but this is not the best choice for your example (you can find some examples in the section below, just in case)
See also:
Valuechangelistener Doubt in JSF
JSF 2 valueChangeListener example
When to use valueChangeListener or f:ajax listener?

Debugging JSF Life Cycle - what exactly happens in each phase

I have decided to dig completely into JSF 2.0 as my project demands deep knowledge of it. I am reading JSF Lifecyle Debug, a well written and awesome article on JSF Life cycle. While reading this article, I have following confusions.
If it's an initial request, in Restore View Phase an empty View is created and straight Render Response Phase happens. There is no state to save at this point. What actually happens in render response phase then? I am confused a little while I am running the example.
The article states that, retrieved input value is set in inputComponent.setSubmittedValue() in Apply Request Values phase. If validation and conversion passes, then the value gets set in inputComponent.setValue(value) and inputComponent.setSubmittedValue(null) runs. On same point article states that, now if in the next post back request, value is changed, it is compared with the submitted value which would always be null on every post back, value change listener will be invoked. It means if, we don't change the value even, as submittedValue would be null, valueChangeListener will always be invoked? I am confused on this statement. Can someone elaborate on this?
Article states the usage of immediate attribute. If immediate attribute is set on an input component, than ideally Process Validation Phase is skipped, but all of the conversion and validation happens in Apply Request Values. My point is, still when the conversion and validation is happening, what's the advantage of skipping the third phase?
What does the term retrieved value means?
I would like to know, if lets say there are five fields on the view. Does JSF makes a list of some collection of these values and Apply Request Values and Process Validations phase iterate over them one by one?
At the last point of this article where it states, when to use immediate attribute. As per my understanding, if immediate attribute is set in both input component and command component, It will skip the phases from Apply Request Values to Invoke Application for any attribute not having immediate. Then what does the last statement mean "Password forgotten" button in a login form with a required and immediate username field and a required but non-immediate password field.
I know these are very basic confusions but clarity on these topics will definitely help sharpen the JSF knowledge.
1: What actually happens in render response phase then?
Generating HTML output for the client, starting with UIViewRoot#encodeAll(). You can see the result by rightclick, View Source in webbrowser (and thus NOT via rightclick, Inspect Element in webbrowser, as that will only show the HTML DOM tree which the webbrowser has built based on the raw HTML source code and all JavaScript events thereafter).
2: it is compared with the submitted value which would always be null on every post back
Nope, it's being hold as an instance variable. JSF doesn't call getSubmittedValue() to compare it.
3: My point is, still when the conversion and validation is happening, what's the advantage of skipping the third phase?
This is answered in the bottom of the article, under Okay, when should I use the immediate attribute?. In a nutshell: prioritizing validation. If components with immediate="true" fail on conversion/validation, then components without immediate="true" won't be converted/validated.
4: What does the term retrieved value means?
The "raw" value which the enduser has submitted (the exact input value which the enduser entered in the input form). This is usually a String. If you're familiar with servlets, then it's easy to understand that it's exactly the value as you obtain by request.getParameter().
5: Does JSF makes a list of some collection of these values and Apply Request Values and Process Validations phase iterate over them one by one?
Almost. The collection is already there in flavor of the JSF component tree. JSF thus basically iterates over a tree structure, starting with FacesContext#getUIViewRoot().
6: Then what does the last statement mean "Password forgotten" button in a login form with a required and immediate username field and a required but non-immediate password field.
This way you can reuse the login form for the "password forgotten" case. If you submit the "login" button, then obviously both the username and password fields must be validated. However if you submit the "password forgotten" button, then the password field shouldn't be validated.
That said, you may find the below JSF phases/lifecycle cheatsheet useful as well for a quick reference:
fc = FacesContext
vh = ViewHandler
in = UIInput
rq = HttpServletRequest
id = in.getClientId(fc);
1 RESTORE_VIEW
String viewId = rq.getServletPath();
fc.setViewRoot(vh.createView(fc, viewId));
2 APPLY_REQUEST_VALUES
in.setSubmittedValue(rq.getParameter(id));
3 PROCESS_VALIDATIONS
Object value = in.getSubmittedValue();
try {
value = in.getConvertedValue(fc, value);
for (Validator v : in.getValidators())
v.validate(fc, in, value);
}
in.setSubmittedValue(null);
in.setValue(value);
} catch (ConverterException | ValidatorException e) {
fc.addMessage(id, e.getFacesMessage());
fc.validationFailed(); // Skips phases 4+5.
in.setValid(false);
}
4 UPDATE_MODEL_VALUES
bean.setProperty(in.getValue());
5 INVOKE_APPLICATION
bean.submit();
6 RENDER_RESPONSE
vh.renderView(fc, fc.getViewRoot());
See also:
Difference between Apply Request Values and Update Model Values
JSF - Another question on Lifecycle
What's the view build time?

JSF page navigation failing with NullPointerException

I wrote two pages...one a form where data submitted and second just to confirm the transaction actually carried out some calculation.
I have a managed bean i.e. FormDataBean and a class Reservation.java from which i instantiate for each booking made. Now I have at the end of a form a submit button:
<h:commandButton value="Submit" action="confirmation"/>
in the bean I have setters and getters as usual. in a method i defined I create an instance of Reservation, then set the beans variables to the instance variabels, like
reservation.startDate = startDate;
reservation.endDate = endDate;
reservation.checkRange();
The last method, i.e. checkRange() will use the assigned values to instance variables to carry calculation. it should return a string successful or failure.
Now when I enter data in the form, and press submit, it just refreshes the page but nothing is submitted. because it doesn't go to next page :(
Any idea what is happening? I don't need to define a navigation rule, because in other project, I carry out simple calculation and display result in next page and it worsks! Please advice
Thanks,
Your are missing to tell us some of the more important details so the answer is a kind of guesswork.
As you don't use navigation rules I assume you are using JSF 2, aren't you?
With JSF 2 you can directly set the new navigation target, without navigation rules. A forward to "confirmation" should work if your outcome file is named confirmation.xhtml. Check that. With a navigation rule you could forward it do a different file.
This part should work regardless of the rest.
For the bean not getting any values make sure that you are using the correct scope either through annotation or entry in your faces-config.xml. As you have a quite unusal validation mechanism you probably have to use the session scope.
The correct way would be using an actionlistener that does your checks and then sets the navigation depending on your checks. The bean scope could be more restrictive then.
Did you try action="confirmation?faces-redirect=true"?

Audit trail for JSF application - Global valueChangeListener possible?

I am trying to implement an audit trail functionality for my web application that records:
lastModified (timestamp)
modifiedBy (user information)
userComment (reason for value change)
for each of my input fields (input fields are spread over several forms with different backing beans and different valueHolder classes).
The first two (lastModified and modifiedBy) are easily done with the help of an JPA AuditListener and #PrePersit and #PreUpdate methods.
The third one is a bit tricky since it requires user interaction. Best would be a dialog that asks for the user comment.
So there are (at least) two open issues: Can I establish a "global" valueChangeListener for all input fields in my application? Is this possible without attaching <f:valueChangeListener> to each single input component? Second: How can I grab the user comment. My idea is to put a p:dialog in my web page template but this dialog needs to know from which input component it is called.
Can I establish a "global" valueChangeListener for all input fields in my application? Is this possible without attaching to each single input component?
Yes, with a SystemEventListener which get executed during PreRenderViewEvent. You need to walk through the component tree as obtained by FacesContext#getViewRoot() to find all components which are an instanceofEditableValueHolder (or something more finer-grained) and then add the new YourValueChangeListener() by the addValueChangeListener() method. See also this answer how to register the system event listener: How to apply a JSF2 phaselistener after viewroot gets built?
Second: How can I grab the user comment. My idea is to put a p:dialog in my web page template but this dialog needs to know from which input component it is called.
You could in YourValueChangeListener#processValueChange() set the component in question as a property of some request or view scoped which you grab by evaluateExpressionGet().
Recorder recorder = (Recorder) context.getApplication().evaluateExpressionGet(context, "#{recorder}", Recorder.class);
recorder.setComponent(event.getComponent());
// ...
It will execute the EL and auto-create the bean in its scope if necessary. The bean in turn should also hold the property representing the user comment. Finally, you can use it in your <p:dialog>.
<p>You have edited #{recorder.component.label}, please mention the reason:</p>
...
<h:inputText value="#{recorder.comment}" />

JSF getValue() v.s. getSubmittedValue()

I've been developing a few JSF applications lately and am disturbed with the inconsistency in the web component APIs.
I've noticed that there is extremely unpredictable behavior when calling .getValue() or .getSubmittedValue() on a JSF component object in server side code. Sometimes when I call .getValue() on a drop down list box, I've noticed that I get the value as it was BEFORE I selected my value (so the value from the last page refresh), of which .getSubmittedValue() gets me the correct value, as such:
UIInput name = new UIInput(); // This is the control I have in a bean.
public void submit(ActionEvent ae)
{
someMethod(name.getValue().toString()); // Retrieves the "old" value
someMethod(name.getSubmittedValue().toString()); // Retrieves the correct value
}
Also, I've noticed that calling .getSubmittedValue() on a form field sometimes results in a null pointer exception because that value has not been instantiated in the component object, in which case when I call .getValue() in that circumstance I get the correct value, for example:
HtmlInputText name = new HtmlInputText(); // This is the control I have in a bean.
public void submit(ActionEvent ae)
{
someMethod(name.getValue().toString()); // Retrieves the correct value
someMethod(name.getSubmittedValue().toString()); // Throws NullPointerException
}
Is this just a "quirk" of the JSF framework, or am I just using the API COMPLETELY incorrectly?? Any insight into these two methods would be greatly appreciated. Cheers.
Since this is the #1 result in Google for searching on getValue vs. getSubmittedValue I'd just like to add that the difference between these is critical in validation (i.e. when writing a custom validator)
To quote the API documentation for getSubmittedValue():
This is non-null only between decode
and validate phases, or when
validation for the component has not
succeeded. Once conversion and
validation has succeeded, the
(converted) value is stored in the
local "value" property of this
component, and the submitted value is
reset to null.
Source: http://myfaces.apache.org/core11/myfaces-api/apidocs/javax/faces/component/UIInput.html#getSubmittedValue()
This means that if the validation/conversion has taken place for the binding you are trying to access, you should call getValue() otherwise you'll have to call getSubmittedValue() and deal with parsing it yourself. The order in which these occur seems to be dictated by the order they appear in the UI, but I don't think that's guaranteed. Even if it is, you shouldn't count on that as changing field in your UI shouldn't break your code.
You can detect if the validation/conversion has been done by just looking at what isLocalValueSet() returns. If it returns true, then the valdation/conversion has been done, so you should call getValue(). Otherwise you'll need to call getSubmittedValue() and that'll give you the raw input the user entered and you'll likely want to parse it into something more meaningful.
For example, a calendar object would return a Date object when getValue() was called, but a String object when getSubmittedValue() was called. It's up to your converter to parse the string into a Date so it can be validated.
It'd be great if the JSF spec had a method which would do this for us, but AFAIK it doesn't. If certain dates need to be before other dates, and some are only required in certain circumstances, one will need to write several validators to handle this. So it can easily become an issue. This is similar to the fact that you can't do any kind of validation on a blank field, which means you can't make that field conditionally required. If validation was run on all fields, even blank ones, a custom validator could be written to throw an exception if it should be required and is not. There are some things with JSF which are just a pain; unless/until they're fixed, we just have to deal with them.
To speak to the specifics of the issue in the original post: the difference here is where you're at in the life cycle. The submit method seems like an action listener for a button, which puts it at the end of the life cycle; actions and action listeners are triggered in the "Invoke Application" phase which comes prior to the render response, but after validation. If you're going to program in JSF, you should learn and understand the life cycle. It's worth the time.
To quote the documentation on EditableValueHolder.getSubmittedValue:
Return the submittedValue value of
this component. This method should
only be used by the encodeBegin()
and/or encodeEnd() methods of this
component, or its corresponding
Renderer.
Generally, you would not even be calling getValue. Instead, the component's value attribute should be bound to your model (a bean, maybe). Your business logic would interact with the model, not the component.
If the submitted value is not being set as the value, then I'd guess that some validation is failing. The only problem with that is that your event is being fired. Two guesses for the problem here:
You have a stale reference to the component object.
You've set the immediate attribute on a UICommand which means that the event is fired in a phase where the component will be in an inappropriate state.
It isn't possible to be certain with the information provided.
I work on xpages which are based on JSF so.. it could be the same...
Anyway, getSubmittedValue(); always returns what you see in firebug/chrome develepers network tab. That is value within sent packet. I have it shown (chrome) in headers tab, in form data section, named $$xspsubmitvalue.
On the other hand, getValue() is component specific. <-- not 100% sure here.
TL;DR answer:
UIViewRoot viewRoot = context.getViewRoot();
UIInput input = (UIInput)viewRoot.findComponent(":form:inputID");
String inputValueString;
if (input.isLocalValueSet()) {
inputValueString = (String)input.getValue(); //validated and converted already
} else {
inputValueString = (String)input.getSubmittedValue(); //raw input
}
or at least that's what the other answers are saying to do...
Just use .getSubmittedValue() and deal with the consequences of having to convert raw input (if necessary, if that raw input needs conversion). .getValue() is broken in this regard, even with the code above. It delays the submitted value if you use it and that's unacceptable.

Resources