TriadWorks - Injetando beans do Spring em conversores e validadores do JSF
public ClienteBean {
@ManagedProperty("#{clienteDao}")
// código do managed bean
No código acima, o container do JSF irá avaliar a EL (Expression Language) #{clienteDao}, recuperar uma instância válida e injetá-la no managed bean antes de utilizá-lo na páginas. Se o JSF estiver integrado ao Spring, a instância de ClienteDao poderá ser obtida do container do Spring.
Contudo, diferentemente dos managed beans, tanto os validadores quanto os conversores do JSF não suportam DI (injeção de dependências) de forma nativa. Por esse motivo, somos obrigados a obter as dependências diretamente dentro dos métodos da classe, o que acaba por diminuir as vantagens do uso de IoC/DI. Uma dessas formas é avaliando uma EL programaticamente, como abaixo:
ClienteDao dao = facesContext.getApplication()
.evaluateExpressionGet(context, "#{clienteDao}", ClienteDao.class);
Para resolver isso, podemos tornar os conversores e validadores gerenciados pelo container do JSF, através das anotações @ManagedBean e @ManagedProperty; ou melhor, podemos passar essa responsabilidade para o container do Spring. Para isso, bastaria anotá-los com @Component e injetar suas dependências com @Autowired, como a seguir:
public Object getAsObject(FacesContext ctx, UIComponent cp, String value) {
Integer id = new Integer(value);
Cliente cliente = this.dao.busca(id);
public String getAsString(FacesContext ctx, UIComponent cp, Object value) {
return cliente.getId().toString();
Agora, para registrar este conversor nos componentes das nossas páginas, bastaria ter um código similar a este:
<h:selectOneMenu value="#{bean.clientes}" converter="#{clienteConverter}">
Ou usando a tag f:converter:
<f:converter binding="#{clienteConverter}" />
Repare que para registrar o conversor no componente, temos que passar a instância do conversor através de EL (Expression Language). O mesmo se aplica para os validadores gerenciados pelo Spring ou mesmo pelo container do JSF.
Outro detalhe para o caso do conversor é que acabamos perdendo o recurso forClass da anotação @FacesConverter que nos permite registrar automaticamente o conversor em componentes que tenham uma EL apontando para um determinado tipo de objeto, neste caso, para o tipo Cliente.
A vantagem de ter um conversor gerenciado pelo Spring é que ganhamos todo o poder e robustez de seu container e podemos aproveitar todos seus recursos, como controle transacional, cache, AOP (programação orientada a aspectos), entre outros.
Outra maneira de habilitar DI para classes anotadas com @FacesConverter e @FacesValidator é através do OmniFaces, com ele podemos injetar beans do CDI e até EJBs. Para isso, basta adicionarmos o JAR do OmniFaces no classpath da aplicação. Nenhuma modificação precisa ser feita nas classes!
Se você usa o MyFaces CODI, você pode utilizar a anotação @Advanced para obter o mesmo resultado.
Apesar das melhorias no JSF 2.2, o suporte a DI em objetos gerenciados por seu container ainda está incompleto e provavelmente só será concluído na sua versão 2.3. Enquanto isso, temos que contornar o problema com o auxílio de outros frameworks.
O ideal é que todos os objetos do JSF passem a ser gerenciados por um container mais robusto, como Spring ou CDI. Para você ter idéia, as anotações do JSF já começaram a ser depreciadas e, em futuras versões da JEE, usaremos apenas as anotações do CDI.
Para entender melhor sobre Spring e JSF, conheça o nosso curso de JSF 2 com Spring, nele estudamos com profundidade a integração entre estes dois frameworks líderes de mercado.
E você, o que tem feito para acessar beans do Spring ou CDI dentro dos conversores e validadores do JSF?