If I correctly combined the information contained in BalusC\'s great 2006 post http://balusc.blogspot.ch/2006/09/debug-jsf-lifecycle.html with Optimus Prime\'s even earlier
Almost correct. The component's local value is only set when conversion and validation is successful. After that, the submitted value is set to null
. You can find the entire process of the validations phase in a rather self-documenting way in the UIInput#validate() method (line numbers are conform JSF 2.1 API):
934 public void validate(FacesContext context) {
935
936 if (context == null) {
937 throw new NullPointerException();
938 }
939
940 // Submitted value == null means "the component was not submitted
941 // at all".
942 Object submittedValue = getSubmittedValue();
943 if (submittedValue == null) {
944 return;
945 }
946
947 // If non-null, an instanceof String, and we're configured to treat
948 // zero-length Strings as null:
949 // call setSubmittedValue(null)
950 if ((considerEmptyStringNull(context)
951 && submittedValue instanceof String
952 && ((String) submittedValue).length() == 0)) {
953 setSubmittedValue(null);
954 submittedValue = null;
955 }
956
957 Object newValue = null;
958
959 try {
960 newValue = getConvertedValue(context, submittedValue);
961 }
962 catch (ConverterException ce) {
963 addConversionErrorMessage(context, ce);
964 setValid(false);
965 }
966
967 validateValue(context, newValue);
968
969 // If our value is valid, store the new value, erase the
970 // "submitted" value, and emit a ValueChangeEvent if appropriate
971 if (isValid()) {
972 Object previous = getValue();
973 setValue(newValue);
974 setSubmittedValue(null);
975 if (compareValues(previous, newValue)) {
976 queueEvent(new ValueChangeEvent(this, previous, newValue));
977 }
978 }
979
980 }
As to the immediate
attribute on the UIInput
component, yes this merely shifts the validation to the apply request values phase. See also the source code of UIInput#processDecodes() and UIInput#processValidators(), there's a check on UIInput#isImmediate()
.