Converter JSF com Spring

 

Olá Pessoal,

O post de hoje será bem rápido. Se você está  precisando criar um Converter e fazer com que este seja gerenciado pelo Spring, o que fazer? Ao olhar a documentação do Spring não há nenhuma anotação direta para o Converter. Lets go! Vamos ver na prática como fazer isso…

 

Converter

Um resumo rápido: Sabemos que quando precisamos carregar um selectOneMenu, por exemplo, um valor customizado, é preciso ter um converter, como por exemplo se preciso carregar cidade, estado, status,  etc é necessário ter um converter, e para implementarmos um converter temos que criar uma classe que implementa a interface Converter do JSF. Nada de especial até aqui, certo?

@FacesConverter( value= “com.camilolopes.readerweb.TypeConverter”,forClass=Type.class)

public class TypeConverter implements Converter {

       @Override

public Object getAsObject(FacesContext context, UIComponent component, String value) {

 

return null;

       } 

       @Override

public String getAsString(FacesContext arg0, UIComponent arg1, Object value) {

             

return null;

       } 

}

Mas você está usando o Spring e quer que seu Converter seja gerenciado por ele, e ainda assim poder chamar as classes de serviços, como fazer? Veja o código alterado com Spring e chamando um método na classe de serviço: 

@Component(“typeConverter”)

public class TypeConverter implements Converter {

       @Autowired

       private TypeServiceImpl typeServiceImpl;

       @Override

public Object getAsObject(FacesContext context, UIComponent component, String value) { 

              Type type = typeServiceImpl.searchById(Long.valueOf(value));

              return type;

       } 

       @Override

       public String getAsString(FacesContext arg0, UIComponent arg1, Object value) {

                     if(value!=null){

                           return ((Type)value).getId().toString();

                     }

              return null;

       } 

       public TypeServiceImpl getTypeServiceImpl() {

              return typeServiceImpl;

       } 

       public void setTypeServiceImpl(TypeServiceImpl typeServiceImpl) {

              this.typeServiceImpl = typeServiceImpl;

       } 

}

Basta anotar com @Component e definir um id para o converter. Na página XHTML chamaremos o id usando EL, veja:

<p:selectOneMenu value=“#{userController.selectedType}” converter=“#{typeConverter}”>

<f:selectItems  itemLabel=“#{type.description}” itemValue=“#{type}” var=“type”  value=“#{typeController.listTypes}” />

</p:selectOneMenu>

Pronto, assim temos o converter via Spring. Claro que você precisar ter no seu face-config.xml na tag <application />

<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>

 Dizendo para o JSF que o Spring vai cuidar da instanciação dos objetos etc. Veja nesse post.

Por hoje é isso. See ya!!

Internacionalização sua aplicação com JSF

Olá Pessoal,

No post de hoje veremos como internacionalizar nossa aplicação JSF.  Eu acho o suporte de internacionalização do JSF muito simples e fácil. É comum você trabalhar em um projeto e o cliente falar que deseja dar suporte pelo menos a 2 idiomas: um default e +1. Veremos como preparar nossa aplicação para isso. Lets go…

Starting…

O JSF procura os arquivos de tradução em um local, que é dentro de resources / src/main/resources, então é lá que vamos colocar os .properties para cada idioma que a aplicação vai suportar. No exemplo aqui será português e inglês, portanto crie dois arquivos .properties chamado: language_en_US e language_pt_BR.  O nome language pode ser qualquer outro. O que teremos nele? Como qualquer arquivo de properties um key=value, é nele que vamos colocar a tradução da aplicação dos labels, message etc. Dentro de src/main/resources crie o seguinte package: com/camilolopes/readerweb/idiom, é onde ficarão nossos arquivos .properties. Poderia deixar na raiz, mas quis colocar em package para ficar organizado.

 

jsfinterproperties

Feito isso, abra o seu face-config.xml e faça isso dentro de application:

<locale-config>

   <default-locale>pt_BR</default-locale>

   <supported-locale>pt_BR</supported-locale>

   <supported-locale>en_US</supported-locale>

  </locale-config>

  <!– Local where is .properties –>

  <resource-bundle>

       <base-name>com.camilolopes.readerweb.idiom.language</base-name>

       <!–  variable will be used in system of context –>

       <var>language</var>

  </resource-bundle>

 

Observe que criamos uma variável. É ela que vamos usar no XHTML passando o key do .properties para que possa ser traduzido com base no idioma definido no browser.

Colocando tradução no .properties

Eu particularmente gosto muito do plugin Resource Bundle http://sourceforge.net/projects/eclipse-rbe/ , pois ele me permite de uma única vez atualizar os dois arquivos  .properties, já inserindo a tradução, veja:

 

jsfpropertiesbundle

Se você usa o Eclipse é só instalar o plugin, mas ele não está no Eclipse Market, é old school, ou seja, você vai na pasta plugin do seu eclipse e cola todo o conteúdo de plugin que está no resource bundle que você acabou de baixar.

Usando na Prática

<h:outputLabel value=“#{language[‘label.type.description’]}” for=“name” />

<h:commandButton value=“#{language[‘command.save’]}” />

 

Resultado:

jsfinterlabelenglish

 

jsfinterlabelpt

Simples, não? Conheça API I4JSF

Espero que tenham gostado. See ya!!!

Abraços.

Overview I4JSF API for JSF Internationalization

Olá Pessoal,

O post de hoje é um pouco diferente. O objetivo é apresentar para vocês o I4JSF API. Ué, mas que API é essa, Camilo? É uma API para JSF com o objetivo de ajudar a evitar a repetição de código para internacionalização. Sim, mas por que usar essa API? Qual o ganho?

 Vamos conhecer a seguir.

Lets go…

O contexto

Antes de apresentar a API vamos entender alguns contextos que já passei e foi de onde veio a ideia de criar I4JSF API que ainda está “verde” e na sua primeira versão. Quando trabalhamos apenas com 1 projeto JSF é comum em alguns casos criar uma classe utilitária para o código de internacionalização, ou melhor, o trecho de código que trata em adicionar uma mensagem no contexto do JSF, independente se veio de um bundle  ou  uma String direta.  Nada de errado aqui. Mas e quando na empresa que você trabalha há mais de um projeto JSF? E que em algum momento há algo em comum referente à implementação entre eles?

Por exemplo, identifiquei que em 2 projetos JSF ambos tinham uma classe para tratar de maneira mais produtiva sem perder a qualidade, com código utilitário, que era criando uma classe utilitária. Daí pensei “se existe uma API em comum, não seria melhor para os dois projetos, desde a melhoria até a manutenção desse código semelhante? Quanto os desenvolvedores gastaram para criar a classe utilitária que normalmente era um código necessário, mas que não estava associado às regras de negocio do projeto, porém era preciso escrever para facilitar o trabalho?”.

I4JSF

Assim nasceu I4JSF API, com o objetivo de evitar esse retrabalho em equipes que usam JSF e vão precisar internacionalizar aplicação e não querem fazer uma classe utilitária para cada projeto JSF.  No GitHub da API você pode encontrar todas as informações de como usar, adicionar ao seu pom.xml ou fazer o download do .jar e ainda há um projeto demo I4JSFDemo, que é um JEE Project que mostra I4JSF in Action.

Claro que há muito trabalho para ser feito e adicionando API, afinal de contas ela acabou de nascer e ai temos uma oportunidade caso deseje contribuir para o desenvolvimento. Veja como:

  1. Faça um fork do projeto no Github;
  2. Implemente a melhoria;
  3. Envie sua mudança;

Um exemplo de uso. Veja a comparação de código usando I4JSF com o código natural do JSF:  

Natural JSF

FacesContext facesContext = FacesContext.getCurrentInstance();

    ResourceBundle bundle = facesContext.getApplication().getResourceBundle(facesContext, “language”);

    String byndleKey = “msg.error”;

    String msgBundle = bundle.getString(bundleKey);

    addFacesMessage(facesContext, msgBundle);

 I4JSF

new I4JSF().addTranslateContext("language", "msg.error");

FAQ

Se for preciso adicionar uma mensagem no contexto JSF via bundle, como faço?

– Simples, chame o método public void addTranslateContext(String bundleVar, String keyProperties) e passe o nome da variável bundle declarada  e a key do bundle e a API se encarrega do resto.

Quero adicionar uma mensagem via bundle para um componente específico, posso?

– Sim. Chame o método addTranslateContext() passando o componentId,variavelBundle e key do bundle

Preciso adicionar uma mensagem para um component, informar a serverity e a mensagem direta. É possível?

– Sim, chame addMessageFaceContext(componentid,serverity, message)

 Preciso adicionar apenas uma mensagem ao contexto, como fazer?

Chame addFacesMessages() passando o FacesContext e  a mensagem que deseja

 Como adicionar uma mensagem para um severity específico sem especificar o component Id?

Chamando  addMessageFaceContext(severity,message).

GitHub 

https://github.com/camilolopes/I4JSF-API

Example Project

https://github.com/camilolopes/I4JSFDEMO

Vou ficando por aqui e aguardo os forks de vocês

Abraços, see ya!!! 

Troubleshooting maven war plugin failure com JSF Project

Olá Pessoal,

Hoje veremos um troubleshooting com maven. Se você já criou um projeto maven e depois adicionou funcionalidade do JSF ao projeto e ao realizar  mvn install teve a mensagem a seguir…

BUILD FAILURE

[INFO] ————————————————————————

[INFO] Total time: 2.321s

[INFO] Finished at: Sat Feb 02 16:34:52 BRST 2013

[INFO] Final Memory: 6M/15M

[INFO] ————————————————————————

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-war-plugin:2.1.1:war (default-war)

 

…Certamente você ficou muito irritado. Na primeira vez eu não fiquei, mas  depois de um tempo sim. Bem, a questão é que ao adicionar as funcionalidade do JSF ao seu maven project,  a estrutura do seu projeto fica diferente do que é esperado por default pelo plugin do maven que gera o war.

O que ele espera: suapp\web-inf\web.xml

Mas o que é na realidade: \suapp\WebContent\WEB-INF\web.xml

Então, o que fazer?

Simples, adicione o plugin a seguir ao seu pom.xml

<plugin>

                    <groupId>org.apache.maven.plugins</groupId>

                    <artifactId>maven-war-plugin</artifactId>

                    <configuration>

                    <webXml>..\suapp\WebContent\WEB-INF\web.xml</webXml>

                    </configuration>

             </plugin>

 

O caminho do web.xml pode variar de acordo como está seu projeto, na dúvida clique com o botão direito no web.xml do projeto e vá na opção copy qualified name  e cole no bloco de notas e assim você obtém o caminho completo.

Bom, é isso ai. Vou ficando por aqui.

Abraços, see ya!! 

TroubleShooting: Fazendo deploy via Maven + JSF Project

 

 

Olá Pessoal,

O troubleshooting de hoje é um problema que descobri ao tentar usar Maven + JSF Project  +  qualquer Server APP. Você deve tá se perguntando: Como assim? Não entendi. Calma que vou explicar.

Lets go…

O problema

Se você criou projetos no Eclipse usando o Jboss tools e decidiu criar um projeto JSF Project  que temos no Jboss tools, vai ter um problema na hora que precisar fazer um quick start deplostart deploy usando algum plugin dos servidores de aplicação a seguir: jetty, jboss e tomcat. Mas, qual o problema?

Simples. Quando criamos um JSF Project todo o conteúdo para web vai ficar na pasta WebContent e ai que começa o problema, pois esta pasta não é padrão do maven e quando fazemos um deploy usando algum plugin dos app servers, simplesmente vamos ver que  suas páginas (.jsp, .xhtml etc) não serão copiadas junto com .war gerado pelo maven e ao acessar sua aplicação verá o error 404. E agora, como resolver?

A solução

Para resolver o problema não encontrei outra solução senão copiar tudo que tinha dentro de WebContent e colocar dentro de webapps, deixando assim:

 mavenwebapps

Execute o seguinte comando:

mvn eclipse:clean

Em seguida

 mvn eclipse:eclipse –Dwtpversion=2.0

No Eclipse, dê um refresh no projeto.

Clique com o botão direito no projeto e vá em properties e verique se está conforme a imagem a seguir. Caso tenha referência para WebContent, basta remover.

mavendeploymentassembly

Agora é só fazer o deploy com o seu servidor de preferência. Claro, é preciso ter o plugin do servidor adicionado ao pom.xml.

Vou ficando por aqui. Ah, há uma solução mais elegante, porém deixarei para o próximo post J

See ya!!

Abraços,