Como Depurar o Ciclo de Vida do JSF (Java Server Faces)

Veja neste artigo como depurar as 6 fases do ciclo de vida do JSF (Java Server Faces) para entender como o JSF se comporta por trás dos panos.

O JSF (Java Server Faces) é um poderoso framework para desenvolvimento de aplicações Web em Java, veio com o intuito de substituir a “velha” interface em JSP por uma mais moderna e de fácil utilização, assim o desenvolvedor não precisa se preocupar com códigos HTML, layout, entre outros aspectos que fogem do real objetivo da aplicação.

Para se utilizar o JSF é necessário o entendimento do seu ciclo de vida, assim o desenvolvedor poderá ter noção do que acontece de forma transparente porém muito importante.

O JSF possui 6 ciclos, são eles:

Explicaremos cada fase através de exemplos práticos do JSF, mas antes precisaremos configurar o Listener que será responsável por monitorar essa mudança de estados do JSF, para isso implementaremos uma interface chamada PhaseListener. Veja na listagem 1 como ficará nossa interface.

package br.com.debugjsf.listener; import javax.faces.event.PhaseEvent; import javax.faces.event.PhaseId; import javax.faces.event.PhaseListener; public class LifeCycleListener implements PhaseListener { public PhaseId getPhaseId() { return PhaseId.ANY_PHASE; } public void beforePhase(PhaseEvent event) { System.out.println("INICIANDO FASE: " + event.getPhaseId()); } public void afterPhase(PhaseEvent event) { System.out.println("FINALIZANDO FASE: " + event.getPhaseId()); } }
Listagem 1. Implementando a Interface PhaseListener

Vamos a explicação do código acima: Criamos uma classe que implementa o PhaseListener, nesta temos os seguintes métodos:

Após termos nosso PhaseListener implementado, vamos configurar o nosso arquivo faces-config.xml para dizer a nossa aplicação quem será o nosso Listener, ou seja, apontar qual será a classe responsável por escutar as mudanças de fase do JSF. Veja na listagem 2 como ficou a configuração do nosso faces-config.xml.

<lifecycle> <phase-listener>br.com.debugjsf.listener.LifeCycleListener</phase-listener> </lifecycle>
Listagem 2. Configurando faces-config.xml

Temos enfim nossa aplicação configurada para escutar todas as fases do JSF, partiremos agora para os exemplos em cada fase. A saída de ciclo completo do JSF no console deve ser algo parecido com a listagem 3.

INICIANDO FASE: RESTORE_VIEW 1 FINALIZANDO FASE: RESTORE_VIEW 1 INICIANDO FASE: APPLY_REQUEST_VALUES 2 FINALIZANDO FASE: APPLY_REQUEST_VALUES 2 INICIANDO FASE: PROCESS_VALIDATIONS 3 FINALIZANDO FASE: PROCESS_VALIDATIONS 3 INICIANDO FASE: UPDATE_MODEL_VALUES 4 FINALIZANDO FASE: UPDATE_MODEL_VALUES 4 INICIANDO FASE: INVOKE_APPLICATION 5 FINALIZANDO FASE: INVOKE_APPLICATION 5 INICIANDO FASE: RENDER_RESPONSE 6 FINALIZANDO FASE: RENDER_RESPONSE 6
Listagem 3. Saída no console de um ciclo completo JSF

Configurando a aplicação de exemplo no JSF

Vamos primeiramente configurar nossa página XHTML, que usaremos para realizar a depuração.

<h:form> <h:inputText binding="#{myBean.inputComponent}" 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.outputComponent}" value="#{myBean.outputValue}" /> <h:messages /> </h:form>
Listagem 4. teste.xhtml

Vamos as explicações:

Vamos agora ver como será nosso ManagedBean.

package br.com.debugjsf.mb; import javax.faces.component.html.HtmlInputText; import javax.faces.component.html.HtmlOutputText; import javax.faces.event.ValueChangeEvent; public class MyBean { //Componentes para Binding private HtmlInputText inputComponent; private HtmlOutputText outputComponent; //Armazena valores dos componentes private String inputValue; private String outputValue; public MyBean() { log("constructed"); } public void action() { outputValue = inputValue; log("succes"); } public HtmlInputText getInputComponent() { log(inputComponent); return inputComponent; } public String getInputValue() { log(inputValue); return inputValue; } public HtmlOutputText getOutputComponent() { log(outputComponent); return outputComponent; } public String getOutputValue() { log(outputValue); return outputValue; } public void setInputComponent(HtmlInputText inputComponent) { log(inputComponent); this.inputComponent = inputComponent; } public void setInputValue(String inputValue) { log(inputValue); this.inputValue = inputValue; } public void setOutputComponent(HtmlOutputText outputComponent) { log(outputComponent); this.outputComponent = outputComponent; } //Escuta por alterações do inputText e escreve no console quando houver public void inputChanged(ValueChangeEvent event) { log(event.getOldValue() + " to " + event.getNewValue()); } //Escreve um LOG no console, para acompanharmos o ciclo de vida private void log(Object object) { String methodName = Thread.currentThread().getStackTrace()[2].getMethodName(); System.out.println("MyBean " + methodName + ": " + object); } }
Listagem 5. MyBean.java

E no nosso faces-config.xml configuraremos o ManagedBean assim como na listagem abaixo.

<converter> <converter-id>myConverter</converter-id> <converter-class>br.com.debugjsf.util.MyConverter</converter-class> </converter> <validator> <validator-id>myValidator</validator-id> <validator-class>br.com.debugjsf.util.MyValidator</validator-class> </validator> <managed-bean> <managed-bean-name>myBean</managed-bean-name> <managed-bean-class>br.com.debugjsf.mb.MyBean</managed-bean-class> <managed-bean-scope>request</managed-bean-scope> </managed-bean>
Listagem 6. Configurando faces-config.xml para o ManagedBean

Vamos recapitular o que temos até agora:

package br.com.debugjsf.util; 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; } }
Listagem 7. Criando o Converter da nossa aplicação
package br.com.debugjsf.util; 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); } }
Listagem 8. Criando o Validator da nossa aplicação

Enfim temos nossa aplicação totalmente criada e configurada para escutar as fases do JSF, é óbvio que você pode adaptar o PhaseListener para sua aplicação, colocamos esta apenas para exemplificar o uso deste.

Conclusão

Enfim, o objetivo deste artigo não é explicar com detalhes o ciclo de vida do JSF, e sim configurar um depurador para acompanhar na prática o ciclo de vida deste framework, pois melhor que a teoria, é a prática. Tendo o conhecimento básico de cada ciclo de vida e acompanhando este depurador, você conseguirá ter uma visão melhor de como funciona tal mecanismo e verá a teoria se aplicando na prática.

Isso porque muitos desenvolvedores sentem dificuldade de “ver” como funciona o ciclo de vida do JSF, pois este é totalmente transparente ao desenvolvedor.

Ebook exclusivo
Dê um upgrade no início da sua jornada. Crie sua conta grátis e baixe o e-book

Artigos relacionados