Listen and debug JSF lifecycle phases
The JSF lifecycle will be explained and debugged here. We'll also check what happens if you add immediate="true" to the UIInput and UICommand and what happens when a ConverterException and ValidatorException will be thrown.
The JSF lifecycle contains 6 phases:
- Restore view
- Apply request values
- Process validations
- Update model values
- Invoke application
- Render response
You can use a PhaseListener to trace the phases of the JSF lifecycle and execute some processes where required. But you also can use a PhaseListener to debug the phases to see what is happening in which phase. Here is a basic example of such a LifeCycleListener:
package mypackage; import javax.faces.event.PhaseEvent; import javax.faces.event.PhaseId; import javax.faces.event.PhaseListener; public class LifeCycleListener implements PhaseListener { public void beforePhase(PhaseEvent event) { System.out.println("BeforePhase: " + event.getPhaseId()); } public void afterPhase(PhaseEvent event) { System.out.println("AfterPhase: " + event.getPhaseId()); } public PhaseId getPhaseId() { return PhaseId.ANY_PHASE; } }
Add the following lines to the faces-config.xml to activate the LifeCycleListener.
<lifecycle> <phase-listener>mypackage.LifeCycleListener</phase-listener> </lifecycle>
This produces like the following in the system output:
BeforePhase: RESTORE_VIEW 1
AfterPhase: RESTORE_VIEW 1
BeforePhase: APPLY_REQUEST_VALUES 2
AfterPhase: APPLY_REQUEST_VALUES 2
BeforePhase: PROCESS_VALIDATIONS 3
AfterPhase: PROCESS_VALIDATIONS 3
BeforePhase: UPDATE_MODEL_VALUES 4
AfterPhase: UPDATE_MODEL_VALUES 4
BeforePhase: INVOKE_APPLICATION 5
AfterPhase: INVOKE_APPLICATION 5
BeforePhase: RENDER_RESPONSE 6
AfterPhase: RENDER_RESPONSE 6
Back to top
Basic debug example
To trace all phases of the JSF lifecycle, here is some sample code which represents simple JSF form with a fake converter and validator and the appropriate backing bean. The code sample can be used to give us more insights into the phases of the JSF lifecycle, to understand it and to learn about it.
The test JSF file: test.jsp
<h:form> <h:inputText binding="#{myBean.inputBinding}" value="#{myBean.inputValue}" valueChangeListener="#{myBean.inputChanged}" > <f:converter converterId="myConverter" /> <f:validator validatorId="myValidator" /> </h:inputText> <h:commandButton value="submit" action="#{myBean.action}" /> <h:outputText binding="#{myBean.outputBinding}" value="#{myBean.outputValue}" /> <h:messages /> </h:form>
The fake converter: MyConverter.java
package mypackage; import javax.faces.component.UIComponent; import javax.faces.context.FacesContext; import javax.faces.convert.Converter; public class MyConverter implements Converter { public Object getAsObject(FacesContext context, UIComponent component, String value) { System.out.println("MyConverter getAsObject: " + value); return value; } public String getAsString(FacesContext context, UIComponent component, Object value) { System.out.println("MyConverter getAsString: " + value); return (String) value; } }
The fake validator: MyValidator.java
package mypackage; import javax.faces.component.UIComponent; import javax.faces.context.FacesContext; import javax.faces.validator.Validator; import javax.faces.validator.ValidatorException; public class MyValidator implements Validator { public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException { System.out.println("MyValidator validate: " + value); } }
The backing bean: MyBean.java
package mypackage; import javax.faces.component.html.HtmlInputText; import javax.faces.component.html.HtmlOutputText; import javax.faces.event.ValueChangeEvent; public class MyBean { // Init ---------------------------------------------------------------------------------------- private HtmlInputText inputBinding; private String inputValue; private HtmlOutputText outputBinding; private String outputValue; // Actions ------------------------------------------------------------------------------------ public void action() { outputValue = inputValue; log("succes"); } // Getters ------------------------------------------------------------------------------------ public HtmlInputText getInputBinding() { log(inputBinding); return inputBinding; } public String getInputValue() { log(inputValue); return inputValue; } public HtmlOutputText getOutputBinding() { log(outputBinding); return outputBinding; } public String getOutputValue() { log(outputValue); return outputValue; } // Setters ------------------------------------------------------------------------------------ public void setInputBinding(HtmlInputText inputBinding) { log(inputBinding); this.inputBinding = inputBinding; } public void setInputValue(String inputValue) { log(inputValue); this.inputValue = inputValue; } public void setOutputBinding(HtmlOutputText outputBinding) { log(outputBinding); this.outputBinding = outputBinding; } // Listeners ---------------------------------------------------------------------------------- public void inputChanged(ValueChangeEvent event) { log(event.getOldValue() + " to " + event.getNewValue()); } // Helpers ------------------------------------------------------------------------------------ private void log(Object object) { String methodName = new Exception().getStackTrace()[1].getMethodName(); System.out.println("MyBean " + methodName + ": " + object); } }
The minimal faces configuration: faces-config.xml
<converter> <converter-id>myConverter</converter-id> <converter-class>mypackage.MyConverter</converter-class> </converter> <validator> <validator-id>myValidator</validator-id> <validator-class>mypackage.MyValidator</validator-class> </validator> <managed-bean> <managed-bean-name>myBean</managed-bean-name> <managed-bean-class>mypackage.MyBean</managed-bean-class> <managed-bean-scope>request</managed-bean-scope> </managed-bean>
Back to top
The first call
The first call should output at least:
BeforePhase: RESTORE_VIEW 1
AfterPhase: RESTORE_VIEW 1
BeforePhase: RENDER_RESPONSE 6
MyBean getInputBinding: null
MyBean setInputBinding: javax.faces.component.html.HtmlInputText@2a9fca57
MyBean getInputValue: null
MyBean getOutputBinding: null
MyBean setOutputBinding: javax.faces.component.html.HtmlOutputText@13bbca56
MyBean getOutputValue: null
AfterPhase: RENDER_RESPONSE 6
1. Restore view.
As the UIViewRoot is empty, there is nothing to do in here.
2. Apply request values.
This phase is skipped because there is no form submit.
3. Process validations.
This phase is skipped because there is no form submit.
4. Update model values.
This phase is skipped because there is no form submit.
5. Invoke application.
This phase is skipped because there is no form submit.
6. Render response.
The components are created for the first time and stored in the UIViewRoot and set in the eventual component bindings. If the component binding getters outputs predefinied components and not null, then those will be used. The values to be shown are retrieved from the value binding getters in the backing bean. If the values aren't set yet, they defaults to null.
Back to top
The refresh
After doing a refresh in the browser in the same user session, the output should look like at least:
BeforePhase: RESTORE_VIEW 1
MyBean setInputBinding: javax.faces.component.html.HtmlInputText@2a9fca57
MyBean setOutputBinding: javax.faces.component.html.HtmlOutputText@13bbca56
AfterPhase: RESTORE_VIEW 1
BeforePhase: RENDER_RESPONSE 6
MyBean getInputValue: null
MyBean getOutputValue: null
AfterPhase: RENDER_RESPONSE 6
1. Restore view.
The components are restored in the UIViewRoot and set in the eventual component bindings.
2. Apply request values.
This phase is skipped because there is no form submit.
3. Process validations.
This phase is skipped because there is no form submit.
4. Update model values.
This phase is skipped because there is no form submit.
5. Invoke application.
This phase is skipped because there is no form submit.
6. Render response.
The values to be shown are retrieved from the value binding getters in the backing bean. If the values aren't set yet, they defaults to null.
Back to top
The form submit
The form submit with the value "test" entered should output at least:
BeforePhase: RESTORE_VIEW 1
MyBean setInputBinding: javax.faces.component.html.HtmlInputText@2a9fca57
MyBean setOutputBinding: javax.faces.component.html.HtmlOutputText@13bbca56
AfterPhase: RESTORE_VIEW 1
BeforePhase: APPLY_REQUEST_VALUES 2
AfterPhase: APPLY_REQUEST_VALUES 2
BeforePhase: PROCESS_VALIDATIONS 3
MyConverter getAsObject: test
MyValidator validate: test
MyBean getInputValue: null
MyBean inputChanged: null to test
AfterPhase: PROCESS_VALIDATIONS 3
BeforePhase: UPDATE_MODEL_VALUES 4
MyBean setInputValue: test
AfterPhase: UPDATE_MODEL_VALUES 4
BeforePhase: INVOKE_APPLICATION 5
MyBean action: succes
AfterPhase: INVOKE_APPLICATION 5
BeforePhase: RENDER_RESPONSE 6
MyBean getInputValue: test
MyConverter getAsString: test
MyBean getOutputValue: test
AfterPhase: RENDER_RESPONSE 6
1. Restore view.
The components are restored in the UIViewRoot and set in the eventual component bindings.
2. Apply request values.
Nothing to see here. In real the values are retrieved from the form and set in the relevant components in the UIViewRoot, for example inputBinding.setValue("test").
3. Process validations.
The values are retrieved as objects from the components, passed through the converter getAsObject() method and validated by the validator. Finally the valueChangeListener is invoked.
4. Update model values.
The converted and validated values will now be set in the value binding setters of the backing bean.
5. Invoke application.
The real processing of the form submission happens here.
6. Render response.
The values to be shown are retrieved from the value binding getters in the backing bean. If a converter is definied, then the value will be passed through the converter getAsString() method and the result will be shown in the form.
Back to top
Add immediate="true" to UIInput only
Extend the h:inputText in the test.jsp with immediate="true":
...
<h:inputText
binding="#{myBean.inputBinding}"
value="#{myBean.inputValue}"
valueChangeListener="#{myBean.inputChanged}"
immediate="true"
>
...
The form submit with the value "test" entered should output at least:
BeforePhase: RESTORE_VIEW 1
MyBean setInputBinding: javax.faces.component.html.HtmlInputText@2a9fca57
MyBean setOutputBinding: javax.faces.component.html.HtmlOutputText@13bbca56
AfterPhase: RESTORE_VIEW 1
BeforePhase: APPLY_REQUEST_VALUES 2
MyConverter getAsObject: test
MyValidator validate: test
MyBean getInputValue: null
MyBean inputChanged: null to test
AfterPhase: APPLY_REQUEST_VALUES 2
BeforePhase: PROCESS_VALIDATIONS 3
AfterPhase: PROCESS_VALIDATIONS 3
BeforePhase: UPDATE_MODEL_VALUES 4
MyBean setInputValue: test
AfterPhase: UPDATE_MODEL_VALUES 4
BeforePhase: INVOKE_APPLICATION 5
MyBean action: succes
AfterPhase: INVOKE_APPLICATION 5
BeforePhase: RENDER_RESPONSE 6
MyBean getInputValue: test
MyConverter getAsString: test
MyBean getOutputValue: test
AfterPhase: RENDER_RESPONSE 6
1. Restore view.
The components are restored in the UIViewRoot and set in the eventual component bindings.
2. Apply request values.
The values are retrieved from the form, passed through the converter getAsObject() method, validated by the validator and the valueChangeListener is invoked. Finally the converted and validated values will be set in the relevant components in the UIViewRoot, for example inputBinding.setValue("test"). This all happens in this phase instead of the Process validations phase due to the immediate="true" in the h:inputText.
3. Process validations.
Nothing to see here. The conversion and validation is already processed in the Apply request values phase, before the values being put in the components. This is due to the immediate="true" in the h:inputText.
4. Update model values.
The values set in the components in the UIViewRoot will now be set in the value binding setters of the backing bean.
5. Invoke application.
The real processing of the form submission happens here.
6. Render response.
The values to be shown are retrieved from the value binding getters in the backing bean. If a converter is definied, then the value will be passed through the converter getAsString() method and the result will be shown in the form.
Back to top
Add immediate="true" to UICommand only
Extend the h:commandButton in the test.jsp with immediate="true" (don't forget to remove from h:inputText):
...
<h:commandButton
value="submit"
action="#{myBean.action}"
immediate="true"
/>
...
The form submit with the value "test" entered should output at least:
BeforePhase: RESTORE_VIEW 1
MyBean setInputBinding: javax.faces.component.html.HtmlInputText@2a9fca57
MyBean setOutputBinding: javax.faces.component.html.HtmlOutputText@13bbca56
AfterPhase: RESTORE_VIEW 1
BeforePhase: APPLY_REQUEST_VALUES 2
MyBean action: succes
AfterPhase: APPLY_REQUEST_VALUES 2
BeforePhase: RENDER_RESPONSE 6
MyBean getOutputValue: null
AfterPhase: RENDER_RESPONSE 6
1. Restore view.
The components are restored in the UIViewRoot and set in the eventual component bindings.
2. Apply request values.
The real processing of the form submission happens here. This happens in this phase instead of the Invoke application phase due to the immediate="true" in the h:commandButton. The UIInput components which don't have immediate="true" set will be ignored completely and therefore their values will not be converted and validated.
3. Process validations.
This phase is skipped due to the immediate="true" in the h:commandButton.
4. Update model values.
This phase is skipped due to the immediate="true" in the h:commandButton.
5. Invoke application.
This phase is skipped due to the immediate="true" in the h:commandButton.
6. Render response.
The values to be shown are retrieved from the value binding getters in the backing bean.
Take care: as the Update model values phase is skipped, the value bindings aren't been set and the value binding getters will return null. The UIInput components which don't have immediate="true" set will be ignored completely and therefore you cannot retrieve the values from the component or value bindings anyway. They will all remain the previous values.
Back to top
Add immediate="true" to UIInput and UICommand
Extend the h:inputText as well as the h:commandButton in the test.jsp with immediate="true":
...
<h:inputText
binding="#{myBean.inputBinding}"
value="#{myBean.inputValue}"
valueChangeListener="#{myBean.inputChanged}"
immediate="true"
>
...
<h:commandButton
value="submit"
action="#{myBean.action}"
immediate="true"
/>
...
The form submit with the value "test" entered should output at least:
BeforePhase: RESTORE_VIEW 1
MyBean setInputBinding: javax.faces.component.html.HtmlInputText@2a9fca57
MyBean setOutputBinding: javax.faces.component.html.HtmlOutputText@13bbca56
AfterPhase: RESTORE_VIEW 1
BeforePhase: APPLY_REQUEST_VALUES 2
MyConverter getAsObject: test
MyValidator validate: test
MyBean getInputValue: null
MyBean inputChanged: null to test
MyBean action: succes
AfterPhase: APPLY_REQUEST_VALUES 2
BeforePhase: RENDER_RESPONSE 6
MyConverter getAsString: test
MyBean getOutputValue: null
AfterPhase: RENDER_RESPONSE 6
1. Restore view.
The components are restored in the UIViewRoot and set in the eventual component bindings.
2. Apply request values.
The values are retrieved from the form, passed through the converter getAsObject() method, validated by the validator, the valueChangeListener is invoked and the converted and validated values will be set in the relevant components in the UIViewRoot, for example inputBinding.setValue("test"). This all happens in this phase instead of the Process validations phase due to the immediate="true" in the h:inputText. Finally the real processing of the form submission happens here. This happens in this phase instead of the Invoke application phase due to the immediate="true" in the h:commandButton.
3. Process validations.
This phase is skipped due to the immediate="true" in the h:commandButton.
4. Update model values.
This phase is skipped due to the immediate="true" in the h:commandButton.
5. Invoke application.
This phase is skipped due to the immediate="true" in the h:commandButton.
6. Render response.
The values to be shown are retrieved from the value binding getters in the backing bean. If a converter is definied, then the value will be passed through the converter getAsString() method and the result will be shown in the form.
Take care: as the Update model values phase is skipped, the value bindings aren't been set and the value binding getters will return null. But the values are still available by the component bindings which are been set in phase Apply request values. In this case you can retrieve the input value from inputBinding.getValue() in the action() method. The new input value is also available by the ValueChangeEvent in the inputChanged() method.
Back to top
Conversion error
Let's see what happens if a conversion error will occur. Change the getAsObject() method of MyConverter.java as follows (and remove the immediate="true" from the test.jsp file):
package mypackage; import javax.faces.component.UIComponent; import javax.faces.context.FacesContext; import javax.faces.convert.Converter; import javax.faces.convert.ConverterException; public class MyConverter implements Converter { public Object getAsObject(FacesContext context, UIComponent component, String value) { System.out.println("MyConverter getAsObject: " + value); throw new ConverterException("Conversion failed."); } ... }
The form submit with the value "test" entered should output at least:
BeforePhase: RESTORE_VIEW 1
MyBean setInputBinding: javax.faces.component.html.HtmlInputText@2a9fca57
MyBean setOutputBinding: javax.faces.component.html.HtmlOutputText@13bbca56
AfterPhase: RESTORE_VIEW 1
BeforePhase: APPLY_REQUEST_VALUES 2
AfterPhase: APPLY_REQUEST_VALUES 2
BeforePhase: PROCESS_VALIDATIONS 3
MyConverter getAsObject: test
AfterPhase: PROCESS_VALIDATIONS 3
BeforePhase: RENDER_RESPONSE 6
MyBean getOutputValue: null
AfterPhase: RENDER_RESPONSE 6
1. Restore view.
The components are restored in the UIViewRoot and set in the eventual component bindings.
2. Apply request values.
Nothing to see here. In real the values are retrieved from the form and set in the relevant components in the UIViewRoot, for example inputBinding.setValue("test").
3. Process validations.
The values are retrieved as objects from the components and passed through the converter getAsObject() method, where a ConverterException is thrown. The validator and the valueChangeListener are bypassed. The lifecycle will proceed to the Render response phase immediately.
4. Update model values.
This phase is skipped due to the ConverterException.
5. Invoke application.
This phase is skipped due to the ConverterException.
6. Render response.
The values to be shown are retrieved from the value binding getters in the backing bean, expecting the values for which a ConverterException has occurred.
Back to top
Validation error
Let's see what happens if a validation error will occur. Change the validate() method of MyValidator.java as follows (and remove the immediate="true" from the test.jsp file and revert MyConverter.java back to original):
package mypackage; import javax.faces.application.FacesMessage; import javax.faces.component.UIComponent; import javax.faces.context.FacesContext; import javax.faces.validator.Validator; import javax.faces.validator.ValidatorException; public class MyValidator implements Validator { public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException { System.out.println("MyValidator validate: " + value); throw new ValidatorException(new FacesMessage("Validation failed.")); } }
The form submit with the value "test" entered should output at least:
BeforePhase: RESTORE_VIEW 1
MyBean setInputBinding: javax.faces.component.html.HtmlInputText@2a9fca57
MyBean setOutputBinding: javax.faces.component.html.HtmlOutputText@13bbca56
AfterPhase: RESTORE_VIEW 1
BeforePhase: APPLY_REQUEST_VALUES 2
AfterPhase: APPLY_REQUEST_VALUES 2
BeforePhase: PROCESS_VALIDATIONS 3
MyConverter getAsObject: test
MyValidator validate: test
AfterPhase: PROCESS_VALIDATIONS 3
BeforePhase: RENDER_RESPONSE 6
MyBean getOutputValue: null
AfterPhase: RENDER_RESPONSE 6
1. Restore view.
The components are restored in the UIViewRoot and set in the eventual component bindings.
2. Apply request values.
Nothing to see here. In real the values are retrieved from the form and set in the relevant components in the UIViewRoot, for example inputBinding.setValue("test").
3. Process validations.
The values are retrieved as objects from the components, passed through the converter getAsObject() method and validated by the validator, where a ValidatorException is thrown. The valueChangeListener is bypassed. The lifecycle will proceed to the Render response phase immediately.
4. Update model values.
This phase is skipped due to the ValidatorException.
5. Invoke application.
This phase is skipped due to the ValidatorException.
6. Render response.
The values to be shown are retrieved from the value binding getters in the backing bean, expecting the values for which a ValidatorException has occurred.
Back to top
Copyright - There is no copyright on the code. You can copy, change and distribute it freely. Just mentioning this site should be fair.
(C) September 2006, BalusC

13 comments:
Thanks BalusC
It's give me good understanding inside JSF .
It's my sugestation that you start post your research on JavaWorld .
Thanks for you help on Sun forum .
With Thanks
Nice post, it helped me to clear JSF lifecycle a bit better. But I still have some doubts. :)
Why MyBean.getInputValue method is called twice, once in BeforePhase: PROCESS_VALIDATIONS and another in BeforePhase: RENDER_RESPONSE, in the form submit (without immediate on either UIInput and UICommand)?
One more thing, you could update the post with a calling to log method at MyBean's constructor. How many instances of a Managed Bean (scoped request) are created by a single JSF Request? This is something I still haven't understood in JSF Lifecycle.
I would be very thankful if you could answer.
Greetings from Brazil. :)
Mauricio
Why MyBean.getInputValue method is called twice
The first time is to compare the old submitted value with the new submitted value. If those values differs, then the valueChangeListener method will be invoked. The second time is just to display the new submitted value.
How many instances of a Managed Bean (scoped request) are created by a single JSF Request?
A request scoped bean is created only once per request. Just copy the code examples into your JSF playground and add a debug statement to the constructor yourself :)
Thanks for answering BalusC, I've been learning a lot reading your posts. :)
So, if there weren't any valueChangeListener in inputText the getIntputValue would be called just once in RENDER_RESPONSE. Is that it?
Ok, I'll add a debug statement in constructor for myself. But if more than one instance of MyBean are created per JSF Request, I'll be back! :)
Thank you one more time.
Mauricio
BalusC,
As others have said, thank you for this great posting. It helps me understand the JSF lifecycle a lot better.
I think that I could use a PhaseListener to check some other conditions and interrupt processing if they are not right. For example, let's say I want it to check user authorization. I have this class:
public class AuthorizationCheck implements PhaseListener {
public PhaseId getPhaseId() {
return PhaseId.RESTORE_VIEW;
}
public void beforePhase(PhaseEvent event) {
if (not userAuthorized()) {
//do something here, like...
//abort processing
//invoke an error view
}
}
public void afterPhase(PhaseEvent event){
return;
}
}
Since I'm pretty new to JSF, I don't know what to do for the "do something". How do I tell the lifecycle to start over with a different view that will show the user an error message?
You can invoke ExternalContext#redirect() to redirect the current request to a new request. It will "automatically" abort the JSF lifecycle as it implicitly calls FacesContext#renderResponse().
Thank you very much, that put me on the right track.
Hi BalusC:
I am in a situation where I need to implement a redirect from the construtor of a managedBean.
For instance :
Page 1 : Has a Name Search feature. Search results navigate to Page 2.
Page 2 : Has Extra information about the name based on DB querries from the DB in the page constructor. To Load data requried to display in Page2. There are hyperlinks on each information on this page that goes to the third Page. Once the information is worked, the related information linked to the name is removed from the DB and I will navigate to Page 2.
The problem that I am not able to resolve is, in the construtor of Page 2 when the DB queries donot return any more information on the name, I need to directly go to Page 1. How can I redirect from the contructor of the second page's specific backing bean.
I tried using Navigation Handler, and setting specific rootView. Netiher works when called from the constructor.
If I implement the PhaseListener, then would the pahse Listener logic be applied to all the other pages in the application ?
Please advice.
Thanks,
Sudeep
I got a work around by using sendRedirect("destinationPage"); in the constructor, however I am not too sure if using sendRedirect or forward is a good practice in JSF.
Could you please advice !
Its really a nice post, which gives the clear understanding of JSF Life Cycle.
All these days I was little confused with the immediate attribute, now its cleared.
Thanks BalusC.
Hi BalusC, great post!
Well, your sample has been performed on JSF1.1, right? Because I'm running your sample on JSF1.2 e I'm getting another result when i perform a "refresh" of the page, in fact, i get the same result from the "first call" to "refresh":
BeforePhase: RESTORE_VIEW 1
AfterPhase: RESTORE_VIEW 1
BeforePhase: RENDER_RESPONSE 6
MyBean getInputBinding: null
MyBean setInputBinding: javax.faces.component.html.HtmlInputText@187fafc
MyBean getOutputBinding: null
MyBean setOutputBinding: javax.faces.component.html.HtmlOutputText@6ecec5
MyBean getInputValue: null
MyBean getOutputValue: null
AfterPhase: RENDER_RESPONSE 6
So, Did JSF1.2 change something in this aspect?
Thanks.
Wonderful Post, I use this site as a referance to just about anything to do with JSF.
One Question. I have a getter that calls a query in order to populate a datatable. Since under the normal lifecycle this getter is called in the APPLY_REQUEST_VALUES and the RENDER_RESPONSE does this not double the amount of calls to the Database?
How would you resolve this?
Thanks alot as your blog and when you hosted your site in the Netherlands really helped me out alot.
Just invoke that call only once per request. You can do this using the constructor or initialization block of a request scoped managed bean, or by introducing lazy loading in the getter.
Post a Comment