Encapsule a API do JSF com a classe FacesUtils
Tenha uma classe de utilidades no seu projeto JSF e reutilize código nos seus controllers
A API do JSF não é uma das mais simples de se trabalhar, existem diversos detalhes que podem tornar a vida do desenvolvedor mais difícil a médio e longo prazo. Detalhes contidos no envio de mensagens de erro e sucesso, navegação programática, avaliação de linguagem de expressão (EL), download de arquivos, entre outros podem ser difíceis para programadores iniciantes ou mesmo causar duplicação de código no projeto.
Por exemplo, exibir uma mensagem de erro de lógica de negócio para o usuário é algo muito comum em uma aplicação Web, em JSF esta operação não é complicada, mas sua API acaba deixando o código mais complexo do que o necessário, pois temos que criar a mensagem e adicioná-la ao contexto do JSF:
String sumario = "Senha fraca";
String detalhe = "Informe uma senha com no mínimo 6 caracteres";
FacesMessage facesMessage = new FacesMessage(FacesMessage.SEVERITY_ERROR, sumario, detalhe);
FacesContext facesContext = FacesContext.getCurrentInstance();
facesContext.addMessage(null, facesMessage); // mensagem global
Criar mensagens e adicioná-las no contexto do JSF não é uma tarefa difícil, porém a API do JSF é muito verbosa. Além disso, por se tratar de uma tarefa comum na aplicação, acabamos acoplando o código dos nossos managed beans a diversas classes do JSF, além de ter possíveis problemas de duplicação de código.
Para diminuir este acoplamento e repetição de código, podemos encapsular a criação de mensagens em uma classe comum à todos os managed beans. Esta classe será responsável por isolar todo o acesso a API do JSF e fornecer uma interface pública simples para os nossos managed beans. Esta classe normalmente recebe o nome de FacesUtils
ou JsfUtils
, como a seguir:
public class FacesUtils {
public void exibeErro(String mensagem) {
FacesMessage facesMessage = new FacesMessage(FacesMessage.SEVERITY_INFO, mensagem, mensagem);
FacesContext facesContext = FacesContext.getCurrentInstance();
facesContext.addMessage(null, facesMessage);
}
}
Com a classe FacesUtils
implementada, agora podemos usá-la dentro dos managed beans de forma simples:
@ManagedBean
public class ProdutoBean {
// ...
public void remove(Produto produto) {
try {
// código para remover produto do banco
} catch (Exception e) {
FacesUtils facesUtils = new FacesUtils();
facesUtils.exibeErro("Erro ao remover produto:" + e.getMessage());
}
}
}
A FacesUtils
além de encapsular a forma como uma mensagem de sucesso ou erro é enviada para as páginas, ela também pode encapsular outras operações rotineiras da aplicação e da API do JSF, como renderização de componentes via AJAX:
public class FacesUtils {
// ...
public void repinta(String componente) {
facesContext.getPartialViewContext().getRenderIds().add(componente);
}
}
ou a avaliação de linguagens de expressão (EL):
public class FacesUtils {
// ...
public <T> T avaliaEl(String el, Class<T> clazz) {
return (T) facesContext.getApplication()
.evaluateExpressionGet(facesContext, el, clazz);
}
}
ou a busca de componentes na árvore de componentes, escrita e leitura de objetos em determinados escopos, ou mesmo a limpeza da árvore de componentes:
public class FacesUtils {
// ...
public void limpa(UIComponent componente) {
if (componente instanceof EditableValueHolder) {
EditableValueHolder evh = (EditableValueHolder) componente;
evh.setSubmittedValue(null);
evh.setValue(null);
evh.setLocalValueSet(false);
evh.setValid(true);
}
if (componente.getChildCount()>0){
for (UIComponent filho : componente.getChildren()) {
this.limpa(filho);
}
}
}
}
Opções de métodos não faltam! A idéia é encapsular o uso da API do JSF para simplificar operações básicas na aplicação. A classe FacesUtils
funcionará como um cinto de utilidades para nossa camada de apresentação. Se ela crescer muito em número de métodos, podemos dividá-la em mais de uma classe, como por exemplo uma classe responsável por cuidar somente das mensagens da aplicação e outra para manipulação da árvore de componentes.
Um bom exemplo de classe de utilidades são as classes Faces e FacesLocal do OmniFaces. Ambas possuem um número considerável de métodos úteis que ajudam o desenvolvedor no dia a dia.
Favoreça seu container
Apesar de muitas classes desse tipo trabalharem somente com métodos estáticos, como a Faces
do OmniFaces, eu recomendo sempre delegar o gerenciamento da classe para seu container IoC/DI.
Dessa forma, paramos de dar new na classe FacesUtils
e passamos a injetá-la em todos os nossos managed beans. Para isso, basta delegar a responsabilidade de criar e gerenciar a FacesUtils
para nosso framework IoC, seja ele CDI ou Spring. No caso do Spring, teríamos um código como abaixo:
@Component
@Scope("request")
public class FacesUtils {
// ...
}
Enquanto com CDI teríamos algo semelhante, como a seguir:
@Named
@ResquestScoped
public class FacesUtils {
// ...
}
Se você não trabalha com Spring nem com CDI, você pode delegar para o micro-container IoC/DI do próprio JSF, deste modo a classe seria anotada com @ManagedBean
e seria tratada como outro managed bean.
Ter uma classe de utilidades no projeto é uma boa prática e é mais útil do que imaginamos, pois além de escondermos a API verbosa do JSF, de quebra nós ainda evitamos a duplicação de código! Não é à toa que esta prática é discutida e implementada no nosso curso de JSF 2 com Spring.
E você? Tem utilizado uma FacesUtils
no seu projeto? Que outros métodos você acha interessante ter na classe?
Desenvolvedor e instrutor na TriadWorks
Posted in: facesutilsjavajeejsfjsfutil