Archive

Author Archive

implicit navigation do JSF 2.0

May 18th, 2009 8 comments

O JSF 2 teve o mecanismo de navegação melhorado. Agora além de regras de navegação implícitas foi adicionado um teste que pode ser feito usando a tag <if> dentro do <navigation-case>. E para finalizar a tag <to-view-id> aceita EL, o que torna tudo mais dinâmico.

Mas como são várias coisas, vamos por partes

Implicit Navigation

Agora quando retornamos um outcome na nossa action, caso nenhuma regra de navegação compatível seja encontrada, a navegação implícita entra em cena.

Vamos considerar os seguintes dados

from-view-id outcome to-view-id implícita
/pasta1/view1.xhtml view2 /pasta1/view2.xhtml
/pasta1/view1.xhtml /view2 /view2.xhtml
/pasta1/view1.xhtml /pasta2/view3 /pasta2/view3.xhtml
/pasta1/view1.xhtml view2.groovy /pasta1/view2.groovy
/pasta1/view1.xhtml /outrapasta/view2.groovy /outrapasta/view2.groovy



Acredito que a tabela seja auto explicativa, mas só para consolidar: caso o outcome devolvido comece com “/” será considerado como caminho absoluto, senão a view será procurada na mesma pasta da view que originou a action. Além disso se nenhuma extensão de arquivo for informada, será considerada a mesma extensão da view que originou a action.

E por fim, podemos definir o atributo “faces-redirect=true” para informar que queremos que seja usado um redirect, assim como faríamos com se tivéssemos definido nossa regra de navegação via xml, como por exemplo “meuOutcome?faces-redirect=true“.

Navigation case com <if>

Assim como as implicit navigation, o Seam também tem o <if> como o do JSF 2, porém no Seam esse <if> fica no pages.xml, um arquivo do Seam. Como sempre, vamos ver um exemplo para facilitar o entendimento.

@ManagedBean(name="pessoaBean")
@RequestScoped
public class PessoaBean{
 
	private EntityManager em; //injetado por algum mecanismo
 
	private Pessoa pessoa = new Pessoa();
 
	public void actionSalvar() {
		em.persist(pessoa);
	}
 
	//getters e setters suprimidos
}

agora vamos ver o faces-config.xml

...
<navigation-rule>
	<from-view-id>/cadastroPessoa.xhtml</from-view-id>
	<navigation-case>
		<if>#{pessoaBean.pessoa.id != null}</if>
		<to-view-id>/listagemPessoas.xhtml<to-view-id>
	</navigation-case>
</navigation-rule>
...

No nosso exemplo acima, mesmo sem retornar nenhum outcome, a navegação acontece da view “/cadastroPessoa.xhtml” para a view “/listagemPessoas.xhtml“, graças ao <if> do nosso <navigation-case>. Na expressão do exemplo usei algo bem simples, considerei que se o id da pessoa está diferente de nulo é porque a ação de salvar foi executada com sucesso. Obviamente podemos evoluir esse exemplo, mas como a finalidade aqui é didática acredito que seja sufucuente como está.

EL no <to-view-id>

Para finalizar vamos dar uma olhada no exemplo do uso da EL no <to-view-id>. Vamos ver esse outro exemplo.

@ManagedBean(name="cidadeBean")
@RequestScoped
public class CidadeBean{
 
	private EntityManager em; //injetado por algum mecanismo
 
	private Cidade cidade = new Cidade();
 
	private nextView;
 
	public String actionSalvar() {
		em.persist(cidade);
		nextView = "/listagemCidades.xhtml"
		return "sucesso";
	}
 
	//getters e setters suprimidos
}

E no faces-config.xml temos o seguinte

...
<navigation-rule>
	<from-view-id>/cadastroCidade.xhtml</from-view-id>
	<navigation-case>
		<from-outcome>sucesso</from-outcome>
		<to-view-id>#{cidadeBean.nextView}<to-view-id>
	</navigation-case>
</navigation-rule>
...

Com isso fechamos a parte de NavigationHandler do JSF 2. Na verdade ainda tem como novidade a possibilidade de consultarmos os NavigationCase’s de forma programática. Mas isso eu comento melhor quando for falar do que podemos fazer de forma programática no JSF 2 usando a implementação de referência, Mojarra (pois essas configurações programáticas que irei comentar não são especificadas).

Categories: JavaEE, JSF Tags: , ,

Conversation Scope usando @CustomScoped do JSF 2.0

Apesar do título, o JSF 2 não vai ter um escopo Conversation ou coisa parecida como tem no Seam ou Orchestra. O que vai ter é o suporte direto a escopos personalizados, o que torna simples a criação de um escopo como Conversation.

Nesse exemplo eu desenvolvi um escopo de conversação simples, mas não é difícil melhorá-lo para suportar diversas conversações simultâneas, assimilando a idéia a gente vê que não é nenhum bicho de sete cabeças. Claro que o principal objetivo é o aprendizado de como tudo funciona, e não ficar implementando o que já tem pronto em diversos frameworks.

Vamos então ao exemplo.

@ManagedBean(name="testeBean")
@CustomScoped("#{conversacao}")
public class TesteBean {
 
	private Integer contador;
 
	@PostConstruct
	public void init()
	{
		System.out.println("TesteBean.init()");
		contador = 0;
	}
 
	public void incrementarContador()
	{
		contador++;
	}
	public void iniciaConversacao()
	{
		Conversacao.instancia().iniciar();
	}
	public void finalizaConversacao()
	{
		Conversacao.instancia().finalizar();
	}
 
	public Integer getContador() {
		return contador;
	}
	public void setContador(Integer contador) {
		this.contador = contador;
	}
}

Acima está um managed bean que chamei de “beanTeste”. Coloquei um println no método init() e anotei esse método com @PostConstruct. Na prática isso quer dizer que toda vez que o managed bean for construído esse método será chamado, e consequentemente aparecerá no console. Isso é útil para vermos que o escopo de conversação realmente está funcionando. Já que estamos falando de escopo personalizado, quem faz isso é a anotação @CustomScoped, que recebe como valor uma EL que será resolvida por um EL Resolver que vamos criar.

Agora vamos ver a tela

Contador atualizado via ajax e mantido com a conversação: <h:outputText id="output3" value="#{testeBean.contador}"/>
 
<br/>
 
<h:commandButton action="#{testeBean.incrementarContador}" value="Incrementar Contador">
	<f:ajax render="output3"/>
</h:commandButton>
<h:commandButton action="#{testeBean.iniciarConversacao}" value="Iniciar Conversação">
	<f:ajax render="@none"/>
</h:commandButton>
<h:commandButton action="#{testeBean.finalizarConversacao}" value="Finalizar Conversação">
	<f:ajax render="@none"/>
</h:commandButton>

Tanto o exemplo da tela quanto do managed bean estão simplificados para o nosso exemplo, mas a versão disponível para download contém uns exemplos para testarmos o funcionamento do ajax também.

A idéia do nosso escopo “conversacao” é o mesmo do Seam, ele funciona como request até que seja explicitamente iniciada a conversação. Quando isso ocorre, o escopo passa a ser statefull até que a conversação seja finalizada, fazendo com que ela funcione como request novamente.

Seguindo essa idéia, o contador que aparece na tela não vai sair de “1″ até que a conversação seja iniciada, pois como o escopo é request, toda vez que executamos a ação “incrementaContador” o managed bean será criado novamente (contador = 0), depois a ação será executada (contador = 1) e então a página será renderizada (exibe contador = 1). Agora se a conversação for iniciada o managed bean será mantido entre as requisições, e o contador não será zerado até que a conversação termine.

Para nosso escopo funcionar, precisamos de um ELResolver, que será quem vai conseguir dizer para o faces de onde virá os objetos relacionados ao escopo “conversacao”. Registramos nosso ELResolver no faces-config.xml assim

<?xml version='1.0' encoding='UTF-8'?>
<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
              version="2.0">
 
    <application>
        <el-resolver>br.eti.gilliard.exemplojsf2.conversacao.ConversacaoELResolver</el-resolver>
    </application>
 
</faces-config>

E a implementação fica assim

 
public class ConversacaoELResolver extends ELResolver {
 
	@Override
	public Object getValue(ELContext elContext, Object base, Object property) {
 
		if (property == null) {
			throw new PropertyNotFoundException("A Propriedade não pode ser nula!");
		}
		if (base == null) {
 
			if(Conversacao.NOME_ESCOPO.equals(property.toString()))
			{
				Conversacao conversacao = Conversacao.instancia();
				elContext.setPropertyResolved(true);
				return conversacao;
			}
 
			Conversacao conversacao = Conversacao.instancia();
			return getValue(conversacao, property.toString(), elContext);
 
		} else if (base instanceof Conversacao) {
			return getValue((Conversacao) base, property.toString(), elContext);
		}
		return null;
	}
 
	private Object getValue(Conversacao conversacao, String property, ELContext elContext) {
		Object objeto = conversacao.get(property);
		elContext.setPropertyResolved(objeto != null);
		return objeto;
	}
 
	// os outros métodos foram suprimidos nesse exemplo
 
}

Essa é uma implementação comum de EL Resolver, onde eu uso o objeto retornado por Conversacao.instancia() para localizar as propriedades solicitadas.

Para o jsf um escopo nada mais é do que um java.util.Map, e de fato a classe Conversacao estende ConcurrentHashMap, ou seja, é um Map como pede o jsf. Fora isso os métodos get e put foram sobrescritos para funcionarem de acordo com nossa especificação de conversação, ou seja, se ela não foi iniciada tudo deve funcionar como request, agora quando a conversação é iniciada, os valores passam a ser guardados dentro da sessão do usuário, fazendo assim ficar statefull. Depois que a conversação é finalizada os valores voltam a ser guardados no request.

Antes de ver a implementação da classe Conversacao, o mais importante é entender como o mecanismo de resolução de EL funciona. Como visto no faces-config.xml, não existe nenhuma ligação da nossa implementação de ELResolver com a El “#{conversacao}” que colocamos na anotação @CustomScoped do nosso managed bean. Toda vez que uma EL é encontrada ela é passada para os ELResolvers contidos na aplicação. Obviamente existem outras implementações padrões já disponíveis, e a nossa vai entrar nessa fila. Como nenhuma das outras implementações vai saber resolver essa EL, ela acaba vindo para a nossa implementação, e então quando encontramos o objeto procurado utilizamos o método “ElContext.setPropertyResolved(boolean b)” passando true para informar que não precisa continuar perguntando para os demais ELResolver‘s, pois o nosso já descobriu quem é o objeto.

Existem alguns detalhes que devemos seguir ao implementar um escopo personalizado, como o de avisar, utilizando o novo sistema de eventos do JSF 2, que estamos criando ou destruindo nosso escopo.

Além disso para fazer essa implementação suportar múltiplas conversações seria necessário apenas colocar um nível a mais de mapa na nossa implementação, onde teríamos uma identificação da conversação e então seu contexto. Em vez de um simples Map, ficaria um Map de Map :D . Então para saber qual Map interno devolver a gente buscaria a conversação atual de algum contexto da nossa escolha, e poderíamos deixar um combobox sempre visível na tela para o usuária escolher a conversação que ele quer usar. Novamente nada de novo, tudo igual o funcionamento do Seam, por exemplo.

Agora sim vamos à implementação da classe Conversacao.

public class Conversacao extends ConcurrentHashMap<string,Object>{
 
	private static final long serialVersionUID = 7556965369432050706L;
 
	public static final String NOME_ESCOPO = "conversacao";
 
	private static final String CONVERSACAO_ATUAL = "exemplojsf2.conversacao.ConversacaoAtual";
 
	private boolean conversacaoNaoIniciada = true;
 
 
	private Conversacao() {
	}
 
	public static Conversacao instancia()
	{
		Map<string, Object> sessionMap = FacesContext.getCurrentInstance().getExternalContext().getSessionMap();
		Conversacao conversacao = (Conversacao) sessionMap.get(CONVERSACAO_ATUAL);
		if(conversacao == null)
		{
			conversacao = new Conversacao();
			sessionMap.put(CONVERSACAO_ATUAL, conversacao);
		}
		return conversacao;
	}
 
	public Object get(Object propriedade)
	{
		//se a conversacao nao for iniciada funciona como request
		if(conversacaoNaoIniciada)
		{
			return pegarDoRequest(propriedade);
		}
 
		return super.get(propriedade);
	}
 
	@SuppressWarnings("unchecked")
	private Object pegarDoRequest(Object propriedade)
	{
		Map<string, Object> requestConversation = (Map<string, Object>) FacesContext.getCurrentInstance().getExternalContext().getRequestMap().get(CONVERSACAO_ATUAL);
		if(requestConversation != null)
		{
			return requestConversation.get(propriedade);
		}
		return null;
	}
 
	@Override
	public Object put(String key, Object value)
	{
		//se a conversacao nao for iniciada funciona como request
		if(conversacaoNaoIniciada)
		{
			return colocarNoRequest(key, value);
		}
 
		return super.put(key, value);
	}
 
	@SuppressWarnings("unchecked")
	private Object colocarNoRequest(String key, Object value)
	{
 
		Map<string, Object> requestMap = FacesContext.getCurrentInstance().getExternalContext().getRequestMap();
		Map<string, Object> requestConversation = (Map<string, Object>) requestMap.get(CONVERSACAO_ATUAL);
		if(requestConversation == null)
		{
			requestConversation = new ConcurrentHashMap<string, Object>();
			requestMap.put(CONVERSACAO_ATUAL, requestConversation);
			return requestConversation.put(key, value);
 
		}
 
		return requestConversation.put(key, value);
	}
 
	public void iniciar()
	{
		conversacaoNaoIniciada = false;
		promoverRequestParaConversacao();
		notificarCriacao();
	}
 
	@SuppressWarnings("unchecked")
	private void promoverRequestParaConversacao()
	{
		Map<string, Object> requestConversation = (Map<string, Object>) FacesContext.getCurrentInstance().getExternalContext().getRequestMap().get(CONVERSACAO_ATUAL);
		super.putAll(requestConversation);
	}
 
	private void notificarCriacao()
	{
		ScopeContext context = new ScopeContext(NOME_ESCOPO, this);
		FacesContext facesContext = FacesContext.getCurrentInstance();
		facesContext.getApplication().publishEvent(facesContext, PostConstructCustomScopeEvent.class, context);
	}
 
	public void finalizar()
	{
		notificarFinalizacao();
		conversacaoNaoIniciada = true;
		rebaixarConversacaoParaRequest();
 
	}
 
	@SuppressWarnings("unchecked")
	private void rebaixarConversacaoParaRequest()
	{
		Map<string, Object> requestMap = FacesContext.getCurrentInstance().getExternalContext().getRequestMap();
		Map<string, Object> requestConversation = (Map<string, Object>) requestMap.get(CONVERSACAO_ATUAL);
		if(requestConversation == null)
		{
			requestConversation = new ConcurrentHashMap<string, Object>();
			requestMap.put(CONVERSACAO_ATUAL, requestConversation);
		}
		requestConversation.putAll(this);
		this.clear();
		FacesContext.getCurrentInstance().getExternalContext().getSessionMap().remove(CONVERSACAO_ATUAL);
	}
 
	private void notificarFinalizacao()
	{
		ScopeContext context = new ScopeContext(NOME_ESCOPO, this);
		FacesContext facesContext = FacesContext.getCurrentInstance();
		facesContext.getApplication().publishEvent(facesContext, PreDestroyCustomScopeEvent.class, context);
	}
}

O download do exemplo pode ser feito aqui.

Com certeza deve ter algum errinho nessa implementação, mas se tiver não se desespere, por essas e outras que você certamente deve estar usando um framework mais confiável na tua aplicação do que uma implementação de “fundo de quintal” ;) . De qualquer forma encontrando os errinhos me diga que eu vou corrigindo.

Categories: JavaEE, JSF Tags: , ,

f:ajax no JSF 2.0

Depois de muito tempo sem escrever estou eu aqui de novo falando de JSF 2.0

Neste post irei mostrar como está ficando o suporte a ajax do JSF 2. Já adianto que está ficando bem parecido com o Ajax4Jsf. Em outros posts eu já havia comentado sobre o suporte a ajax que a nova versão do jsf vai suportar. Mas agora vou falar do componente de tela para facilitar o uso, no outro post falei apenas da API JavaScript, que eu usei nesse exemplo.

O componente <f:ajax> parece o <a4j:support>. Essa nova tag pode ser usada tanto dentro de uma tag específica, tornando-a ajax, assim como fazemos com o <a4j:support> ou pode ser colocada em volta de vários componentes, tornando todos os componentes dentro dela ajax.

Por exemplo:

 
<h:panelGroup id="panelGroupX">
...
</h:panelGroup>
 
<h:outputText id="outputY" value="..."/>
 
<h:commandButton action="...">
    <f:ajax execute="@form" render="panelGroupX outputY"/>
</h:commandButton>

Nesse exemplo temos uma página como já estamos acostumados, até onde o novo componente aparece. Nesse caso a tag <f:ajax> está habilitando ajax no commandButton, e os dois principais atributos da tag são “execute” e “render”. O primeiro serve para informarmos o que será enviado ao servidor na nossa requisição ajax, e o segundo é como o “reRender” do ajax4jsf, e serve para informarmos o que será renderizado novamente. Ambos aceitam uma lista de ids, separados por espaço em branco, ou então os seguintes valores pré-definidos:

  • @this – o próprio componente que dispara a requisição ajax
  • @form – o formulário que envolve o componente @this
  • @all – a view inteira
  • @none – nenhum componente

Lembrando novamente que esses valores servem tanto para informar o que vai (execute) e o que volta (render) em uma requisição ajax.

Agora outro exemplo

 
<f:ajax event="onmouseover">
 
    <h:panelGroup id="panelGroupX">
    ...
    </h:panelGroup>
 
    <h:outputText id="outputY" value="..."/>
 
    <h:commandButton action="...">
        <f:ajax event="action" execute="@form" render="panelGroupX outputY"/>
    </h:commandButton>
 
</f:ajax>

Nesse caso a tag <f:ajax> envolve os demais componentes, fazendo com que tudo que está dentro dela passe a disparar eventos ajax. Cada tipo de componente possui um evento padrão que dispara a requisição ajax: um input dispara a requisição quando tem seu valor alterado e um botão ou link quando é clicado, por exemplo.

Porém nesse exemplo eu especifiquei que o evento padrão que executará o ajax para todos os componentes dentro da tag <f:ajax> é o “onmouseover”, mas como mostrado no commandButton eu posso sobrescrever os valores definidos na tag <f:ajax> de fora com uma tag dentro do próprio componente. Eu usei a propriedade “event“, mas poderia ter usado qualquer outra na tag ajax de fora, fornecendo assim um mesmo comportamente default para todos.

No último exemplo usei a propriedade “event“, que como visto no exemplo serve para dizer qual evento executará a requisição ajax. Essa propríedade suporta todos os eventos DOM e ainda “valueChange” para componentes de entrada de dados (ou mais especificamente um EditableValueHolder) e “action” para componentes de ação (um ActionSource).

A tag <f:ajax> suporta ainda os atributos:

  • listener – serve para fazer binding com um método que a seguinte assinatura “public void (javax.faces.event.AjaxBehaviorEvent event) throws javax.faces.event.AbortProcessingException“. Com isso podemos executar um código java quando um evento qualquer é disparado.
  • disabled – seria o equivalente ao rendered de um componente visual, se o valor definido aqui for true o suporta a ajax fica desabilitado.
  • immediate – igual o immediate dos componentes jsf comuns.
  • onevent – função js que será chamada quando o evento especificado for executado
  • onerror – função js que será chamada quando um erro ocorrer na requisição

Esse post foi curto por falta de tempo, mas novos posts virão em breve (assim espero ). Já estou com um exemplo pronto de implementação de conversation usando o suporte a escopos customizados do JSF 2.0, mas isso vai ter que ficar para o próximo post ;)

Categories: JavaEE, JSF Tags: , ,

Exemplo com JSF 2.0

February 2nd, 2009 28 comments

Na última sexta-feira, dia 30/01/2009, realizamos a primeira reunião de 2009 do JUGMS. Foi bem legal, contamos com mais de 100 pessoas. Nosso bate papo teve, além de conversarmos sobre os planos do JUGMS, dois assuntos bem interessantes. O Saulo falou um pouco sobre Análise e Projeto OO em Java, e eu sobre as novidades do JavaEE 6, parando um tempinho a mais na parte de JSF 2.0.

O tempo foi curto, e não deu pra explorar muito o exemplo, mas logo abaixo estou disponibilizando a apresentação (design show de bola :D ) e o projeto de exemplo usando JSF 2. O exemplo foi feito usando Java 6 e tomcat 6.

Alguns pontos que eu procurei mostrar no exemplo foram:

API AJAX do JSF 2.0

No código do exemplo podemos ver trechos de código como este:

...
<h:commandButton value="Salvar" action="#{estadoBean.salvar}"
onclick="return facesAjaxRequest(this, event, {inputs: 'formEstado', render: 'formEstado:listaEstados'})"/>
...

onde eu criei essa função js chamada facesAjaxRequest que encapsula a simples chamada ajax do jsf 2 que seria assim:

jsf.ajax.request(element, event, options);

Essa funçao recebe o elemento que está disparando a ação (normalmente this), o evento e um mapa de parâmetros. Nesse mapa existem duas entradas: execute e render. No render, especificamos, separados pos espaços em branco, os clientIds dos componentes que serão renderizados novamente, e no execute passamos os valores a serem enviados ao server nessa requisição ajax.

No exemplo usei a função facesAjaxRequest para montar dinamicamente a lista que vai no parâmetro execute, por isso este parâmetro não aparece no primeiro exemplo mostrado. Com essa função, podemos ainda passar o id de qualquer elemento html pelo atributo inputs do mapa que todos os inputs e selects que estiverem abaixo desse elemento será enviado para o server. Na tela de cadastro de cidades fiz uma espécie de ajaxRegion usando essa forma bem simples.

Isso tudo porque o JSF 2 não tem algo tão fácil de usar como os componentes da biblioteca ajax4jsf. A idéia dessa biblioteca de ajax de jsf 2 não é deixar tudo mastigadinho, e sim prover uma infraestrutura básica uso padronizado de js nos componentes, eliminando ou diminuindo assim as incompatibilidades entre as bibliotecas de componentes disponíveis.

Update: Na época do Early Draft Review 2 só tínhamos a api js, mas logo depois saiu a tag estilo ajax4jsf e fiz um outro post sobre isso.

Para quem chegou a usar as funções js do Facelets 1.2, que nem chegou a ser continuado, e que eu mostrei num artigo que escrevi pra MundoJava há muito tempo, o funcionamento é quase o mesmo, só mudando praticamente o nome das funções js e a forma como os dados eram enviados ao server.

Facelets 2

Como já foi dito por aí, agora o JSF já vem por default com o Facelets 2 habilitado, não sendo necessário colocar nenhuma configuração para utilizálo. Inclusive no exemplo disponível para download, nem existe o arquivo faces-config.xml, pois fiz tudo por anotações e o Facelets já vem pronto pra uso. Mas é claro que ele continua sendo utilizado para as regras de navegação.

Criação de componentes com Facelets 2

Com facelets 2, a criação de componentes será algo mais “formal” do que fazemos com facelets hoje em dia. Isso graças a presença de uma definição do componente como esse:

...
<composite:interface name="beanSimples">
    <composite:attribute name="bean" required="true">
        <composite:attribute name="descricao" type="String" required="true"/>
    </composite:attribute>
</composite:interface>
 
<composite:implementation>
    Descrição: <h:inputText id="descricao" value="#{compositeComponent.attrs.bean.descricao}"/>
</composite:implementation>
 
...

O componete possui a interface e a implementação. Na interface podemos colocar os parâmetros que serão recebidos, como no exemplo onde eu preciso passar um objeto que eu chamei de “bean” e esse bean tem que ter um atributo do tipo String chamado descrição.

É possível ainda passar atributos que representam ações, o que não é possível hoje em dia. Além disso não é necessário nenhum arquivo para configurar o nosso componente customizado, tudo é feito através de convenção. Basta colocar o componente em uma pasta dentro do resources do jsf que ele já fica publicado e acessível por uma uri default. Mas se quisermos colocar uma uri específica é só indicar através de um arquivo de configuração.

SelectItems

Finalmente podemos usar o componente f:selectItems sem ter que criar uma lista ou array de SelectItem. Agora podemos usar diretamente nossos objetos do modelo como podemos fazer usando outros componentes de selectItems como o do Seam.

<h:selectOneMenu value="#{cidadeBean.cidade.estado}">
    <f:selectItems value="#{estadoBean.estados}" var="estado" itemLabel="#{estado.descricao}" itemValue="#{estado}"/>
</h:selectOneMenu>

Finalizando

O exemplo disponível é bem simples, mas procurei mostrar nele o uso de coisas simples, como as mencionadas acima, e também proporcionar para quem ainda não teve a disposição de começar a testar que já tenha um ponto de partida. Olhando o código fonte podemos ver funcionando também as novas tags para escrever css e js, e explorar a parte de localização de recursos, que é inclusive o que torna a criação de componentes tão simples.

Espero que esse post e os materiais relacionados sejam de utilidade, e caso você encontre algum erro no material disponível me avise comentando aqui ;)

view scope no JSF 2.0

October 24th, 2008 20 comments

Eu uso JSF há um bom tempo e sempre fui um defensor de que JSF é muito bom, mas hoje em dia ainda não da pra usar ele sozinho, por isso mesmo uso JSF + Facelets + Seam. Acredito que com o que temos hoje usar JSF sozinho não é lá das coisas mais produtivas do mundo, e isso em alguns casos faz com que pessoas critiquem o JSF porque não querem adicionar mais dependências ao projeto e deixam Facelets e Seam de fora.

Pessoalmente eu acho isso quase o mesmo nível de querer fazer um projeto sem Hibernate pra não ter mais dependências no projeto. Tá certo que hoje o caso é diferente pois temos a JPA, mas se não a tivéssemos ainda, você faria um projeto de verdade só com JDBC só pra não ter essa dependência com Hibernate? Pois bem, muita gente faz isso com JSF. Mas assim como a JPA veio para deixar as pessoas mais tranquilas e menos apavoradas de ter um framework a mais na aplicação, o JSF 2.0 também vai dar uma forcinha nesse sentido. Com ele poderemos ter uma aplicação funcionando super bem sem adicionar outros frameworks para isso. E isso devido duas coisas: a inclusão do Facelets (já apresentada aqui), e o novo escopo view.

Erros de validação

O JSF faz um papel muito bem feito abstraindo a camada web. Conseguimos desenvolver uma aplicação com JSF sem colocar a mão em HttpServletRequest e outros Http* da vida. O serviço seria muito bem feito de ponta a ponta se não fosse por um detalhe: a falta de um escopo que abstraísse também o http como o restante faz. Até o JSF 1.2 parece que essa parte foi esquecida, e enquanto o Faces tratava os escopos já conhecidos de toda aplicação web, como request, session e application, deixava uma porta aberta para o surgimento de componentes como t:saveState do Tomahawk, e depois as famosas conversations, no Seam.

Mas para que conversation e saveState servem? Um dos maiores problemas do JSF é a quantidade de “erro de validação” que acabam “estourando” na cara do desenvolvedor. Claro que sabendo como o JSF trabalha nós conseguimos desenvolver sem problemas. Eu sempre comento que a regra número 1 é sempre sobrescrever o método equals. Seguir boas práticas nunca é demais. E com isso boa parte dos erros de validação simplesmente somem. Um dia eu paro pra explicar melhor isso. Mas existem erros que acontecem como os famosos combos em cascata e commandButtons/commandLinks que não executam poque estão dentro de dataTable’s que só são preenchidas depois de alguma ação.

Imagine que temos uma página de cadastro de endereço, onde existem dois combos, o primeiro para estado e o segundo para cidades. Mas inicialmente o combo de cidades vem vazio, somente depois que selecionamos o primeiro, uma ação é executada para buscar as cidades. Selecionamos então “MS”, acontece uma nova requisição, as cidades são mostradas, selecionamos “Campo Grande” e mandamos salvar. Nisso vem o famoso erro de validação no combo das cidades. Isso acontece porque pela natureza stateless do managed bean de escopo request que estamos usando, o JSF esquece que já foi feita a requisição que busca as cidades, e para ele quando clicamos em salvar é como se fosse a primeira requisição. Então o JSF pensa: “como esse cara tá submetendo uma cidade sendo que eu nem mostrei os valores desse combo ainda? Essa cara tá me sacaneando, vou tesourar essa requisição dele”. Mas como fugir disso então? Coloca tudo no escopo de sessão? A resposta para esse problema é a utilização de escopos mais refinados, não disponíveis (ainda) no JSF padrão.

Contextos mais “espertos”

Na minha opinião, uma das melhores coisas do Seam é a conversação. Um conversação é um “escopo” maior que um request e menor que a sessão do usuário, e que tem um início e fim definidos por nós. Quando iniciamos uma conversação o contexto “vira” statefull até que seja finalizada, quando então “vira” stateless novamente. Claro que o Seam é muito mais que isso, mas para o assunto do post isso é o mais relevante. Fora Conversation, o Seam tem um escopo Page, cujo funcionamento é basicamente o mesmo do saveState. Dessa forma, o contexto é statefull enquanto submetemos para a mesma página. Uma conversação é algo mais refinado, que pode envolver várias telas, mas para a grande maioria dos casos essas várias requisições que precisamos manter o estado são feitas para mesma tela, como nos exemplos dos combos de estado e cidade e da dataTable resultando de filtro com uma action dentro.

View Scope

Exatamente nesse caso que o escopo view vem suprir essa carência do JSF padrão. Um managed bean com esse escopo permanece na memória enquanto submetemos para a mesma tela. Não quero dizer que você nunca mais vai precisar de outras coisas, ou que o Seam nada mais é do que fazer de outra forma o que um saveState já fazia antes, mas sim que agora para a maioria das aplicações já poderemos usar apenas JSF 2 sem ter que usar outras ferramentas para nos auxiliar. Claro que um conjunto de componentes ricos sempre será bem vindo, e que certamente iremos continuar querendo usar algumas coisas mais específicas que o Seam/WebBeans nos oferecem. Mas o grande ganho é que para o básico não precisamos de mais nada, coisa que infelizmente hoje, com JSF 1.2, ainda não acontece.

Como já escrevi bastante, vamos a um exemplo. O nosso managed bean de escopo view ficaria assim:

@ManagedBean(name="enderecoBean")
@ViewScoped
public class EnderecoBean {
 
    @PostContruct
    public void construct() {
        //chamado só quando o managed bean é colocado no escopo view,
        //e não a cada requisição como acontecia com o escopo request
    }
 
    @PreDestroy
    public void destroy() {
        //chamado quando outra view for chamada através do UIViewRoot.setViewId(String viewId)
    }
 
}

Com esse escopo o JSF cria o managed bean na primeira requisição onde ele for preciso (se for lazy), e só o remove da memória quando for chamado o método UIViewRoot.setViewId(String viewId) para indicar que iremos trabalhar com outra página.

Categories: JavaEE, JSF Tags: , ,

JavaServer Faces 2.0 – Early Draft Review 2

September 24th, 2008 4 comments

Saiu o segundo rascunho da especificação do JSF 2.0, no entanto ainda não há uma versão da implementação da EDR2 disponível para download como já saiu para a EDR1.

Primeiramente, vou me basear nas diferenças entre as reviews 1 e 2, mas isso não significa que o que vou falar aqui é inédito pois podemos ver na net diversos post comentando o que vem por aí. E também ainda não li tudo, a idéia é compartilhar o que mais me chamou a atenção nesse primeiro contato.

FacesContext

Sem dúvida essa é uma das classes que mais manipulamos no JSF, e nela temos algumas funcionalidades novas interessantes:

  • getCurrentPhaseId() – Disponível desde a EDR1, devolve um PhaseId. Pode ser bem útil para fazermos algumas coisas só depois de uma dedeterminada fase.
  • getExecutePhaseClientIds() - Devolve uma List<String>. Guarda uma lista com os client ids dos componentes que serão processados na requisição atual. Isso porque o JSF2 tem nativamente o suporte à ajax, e submissão parcial da página.
  • getPartialResponseWriter() - Devolve o ResponseWriter para os componentes de uma renderização parcial.
  • getRenderPhaseClientIds() - Devolve uma List<String> contendo os client ids dos componentes que serão renderizados em uma renderização parcial.
  • isAjaxRequest() - devolve um boolean dizendo se a requisição é ajax (auto explicativa né :) )
  • isExecuteNone() - retorna true se for uma submissão parcial mas nenhum componente precisará ser processado. Seria como dar apenas um reRender usando o ajax4jsf mas sem mandar executar nada.
  • isPostback() - método "atalho" para ResponseStateManager.isPostback(FacesContext).
  • isRenderAll() - Retorna true se for uma requisição ajax, isRenderNone() retornar falso, e getRenderPhaseClientIds() retornar uma lista vazia.
  • isRenderNone() - Retorna true caso for para executar uma renderização parcial, mas a lista de componentes a renderizar for vazia. Imagine uma requisição ajax que só envia dados ao servidor.

Para os métodos get dessa lista, também tem os respectivos set.

Annotations

Uma coisa que todo mundo esperava está disponível no EDR2, que é a possibilidade de anotar nossos managed beans com @ManagedBean, @FacesValidator, @FacesConverter e @FacesComponent entre outros.

Para quem já está habituado com o Seam vai se sentir bem a vontade, pois as anotações seguem o mesmo estilo.

Apesar de no começo parecer estranho esse prefixo "Faces" em todas essas anotações, fica útil para não confundir com as interfaces com o mesmo nome. Sem isso (no Seam é assim), como importamos a anotação e a interface com o mesmo nome, uma das duas tem que ficar com o nome totalmente especificado. Não que seja problema, mas com esse prefixo fica mais "limpinho".

@ManagedBean

  • name - nome do managed bean
  • scope- escopo. O que não pareceu tão legal é que a gente passa uma String ("request", "session" ou "application"), quando seria mais bacana uma Enum como o Seam faz. O valor default é "none".
  • eager - se for true, o managed bean será startado junto com a aplicação, e o "escope" passado será ignorado, e o managed bean será do escopo application. Se for false, fica como é hoje (lazy). O default é false.

@RequestScoped, @SessionScoped, @ApplicationScoped, @NoneScoped, @ViewScoped, @CustomScoped

  • Cada uma das anotações representando seus respectivos escopos

@FacesConverter

  • value - string que representa o converter-id do conversor
  • forClass - passamos o java.lang.Class da classe que queremos registrar o conversor na forma de converter-for-class

@FacesValidator

  • value - string que representa o validator-id do validador

@FacesComponent

  • value - string que representa o component-type do UIComponente

Facelets 2

O outro assunto que de cara me interessou foi a integração do JSF com o Facelets, pois já uso Facelets há um bom tempo e nem me imagino fazendo uma aplicação em JSF sem ele. Tanto que até escrevi uma matéria pra a MundoJava sobre Facelets e as novidades do JSF 1.2. Na época eu comentei sobre a versão 1.2 do Facelets que nunca chegou a sair, talvez porque o pessoal passou a investir no JSFTemplating ou quem sabe viram que compensaria partir logo para um 2.0. Mas no Facelets 1.2 já podíamos ver o que provavelmente foi a base da API de Ajax para o JSF2.

No JSF2 temos o chamado PDL (Page Declaration Language), que é uma abstração para os mecanismos de definição de páginas disponíveis para o JSF, que até agora são JSP e Facelets. Porém se a gente der uma espiadinha no projeto JSFTemplating, podemos ver que existe a possibilidade de usarmos outras coisas, como Groovy por exemplo. Então é bem possível que vejamos coisas parecidas para o JSF2. Só para concluir a idéia, já é possivel usar Groovy em vez de xhtml para construir telas com Facelets, usando Gracelets. É bem bacana e eu já fiz uns testes que depois vou postar aqui também. Mas vamos voltar ao assunto.

Na EDR2 é explicado como será mantida a compatibilidade retroativa com as aplicações que usam Facelets. Basicamente será procurando dentro das classes da nossa aplicação ou das dependencias dela se existe alguma dependencia de classes do pacote com.sun.facelets e/ou dos seus subpacotes. Se houver, o Facelets embarcado no JSF não vai rodar, e as coisas vão continuar como estão, onde quem roda é o facelets que está no jar da nossa aplicação. Agora se não houver dependencia com as classes do Facelets atual, o Facelets2 entra em ação.

Composition Component com JSF/Facelets 2

Primeiramente, seria interessante dar uma olhada no suporte a recursos do JSF2 para entendermos melhor como tudo vai funcionar. Vou seguir o exemplo da documentação para facilitar.

Um composition component vai ser definifo usando o suporte a resources do JSF2. Imagine que o source do nosso componente é o foo.xhtml que está dentro da pasta ezcomp que por sua vez fica dentro da pasta de resources do JSF. Para usarmos esse componente nao precisamos mais de um arquivo taglib.xml, bastara chamarmos assim:

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml"
 xmlns:h="http://java.sun.com/jsf/html"
 xmlns:f="http://java.sun.com/jsf/core"
 xmlns:ui="http://java.sun.com/jsf/facelets"
 xmlns:ez="http://java.sun.com/jsf/composite/ezcomp">
 
   ...
   <ez:foo />
   ...
</html>

Como podemos ver nossos componentes ficam automaticamente visíveis usando o padrão http://java.sun.com/jsf/composite/<composite-library-name> onde <composite-library-name> é o nome da nossa pasta dentro do resources do JSF. E cada xhtml dentro dessa pasta pode ser acessado como um componente. Vimos aqui um bom exemplo de CoC no JSF2. Agora se quisermos usar um padrão diferente de nomenclatura para nossos componentes, basta usar o bom e velho arquivo de configuração de taglibs do facelets.

Agora ainda seguindo o exemplo disponível na versão snapshot (e provavelmente será a mesma do EDR2), vamos ver como fica o código de um componente definido em um arquivo chamado loginPanel.xhtml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:composite="http://java.sun.com/jsf/composite">
<head>
<title>Not present in rendered output</title>
</head>
<body>
 
<composite:interface name="loginPanel"
                     displayName="Very Simple Login Panel"
                     preferred="true"
                     expert="false"
                     shortDescription="An illustration of the composite component feature">
 
  <composite:attribute name="model" required="true">
 
    <composite:attribute name="loginAction" required="true">
      <composite:deferred-method>
        <composite:method-signature>
                    java.lang.Object action()
        </composite:method-signature>
      </composite:deferred-method>
     </composite:attribute>
 
   </composite:attribute>
 
 
  <composite:editableValueHolder name="username" />
  <composite:actionSource name="loginEvent" />
  <composite:actionSource name="cancelEvent" />
  <composite:actionSource name="allEvents" targets="loginEvent,cancelEvent" />
 
  <composite:facet name="header" />
 
</composite:interface>
 
<composite:implementation>
 
<table border="1">
  <thead>
    <tr>
      <th>
     <composite:insertFacet name="header" />
      </th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>
      <p>
         <h:inputText id="username" />
      </p>
      <p>
	<h:commandButton id="loginEvent" value="Login" action="#{compositeComponent.attributes.model.loginAction}">
 
	</h:commandButton>
	<h:commandButton id="cancelEvent" value="Cancel" action="cancel">
	</h:commandButton>
      </p>
      </td>
    </tr>
    <tr>
      <td>
     <p>This is the login panel footer</p>
     <composite:insertChildren />
      </td>
    </tr>
  </tbody>
</table>
</composite:implementation>
</body>
</html>

Coloquei o código todo, mas o mais importante é da linha 12 até a linha 41, que é onde definimos as características do nosso componente. Isso deve facilitar que ferramentas deem suporte aos nossos componentes, e também a quem for usar esses componentes, pois damos mais informações a respeito das propriedades que ele precisa. A documentação diz que em muitos casos será possível construir componentes sem prover essas informações, deixando mais parecido com o que é hoje, mas diz também que falta definir um limite de até onde pode ser feito um componente sem especificar esse "contrato de uso".

Uma coisa interessante que pode ser vista nesse exemplo é a exigencia de um método chamado loginAction com uma assinatura específica dentro do objeto que for passado no atributo model.

O código que usa esse componente pode ser visto a seguir

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:ez="http://java.sun.com/jsf/composite/ezcomp">
<h:head>
<title>The Simplest EZComp Demo That Could Possibly Work</title>
</h:head>
<h:body>
<p>Login Panel Component</p>
  <ui:debug hotkey="p" rendered="true"/>
<h:form>
  <div id="compositeComponent" class="grayBox" style="border: 1px solid #090;">
 
    <ez:loginPanel id="loginPanelInConsumingPage" model="#{bean}">
 
      <f:valueChangeListener for="username" binding="#{bean.useridValueChangeListener}" />
      <f:actionListener for="loginEvent" binding="#{bean.loginEventListener}" />
      <f:actionListener for="cancelEvent" binding="#{bean.cancelEventListener}" />
      <f:actionListener for="allEvents" binding="#{bean.allEventsListener}" />
 
      <f:facet name="header">
         <h:panelGroup id="headerFacetInConsumingPage">
          <h:outputText value="this is the header facet in the consuming page" />
         </h:panelGroup>
      </f:facet>
      <h:outputText id="childInConsumingPage" value="this is a child component in the consuming page" />
    </ez:loginPanel>
  </div>
<p><h:commandButton value="reload" /></p>
</h:form>
</h:body>
</html>

Nesse exemplo pode reparar da linha 18 a 21 que usamos os composite:actionSource definidos no componente como ganchos para pendurar nossos listeners.

Só lembrando que esses exemplos são em cima da EDR2 do JSF2, então tudo que foi visto aqui pode não ser igual ao que vai estar na versão final.

Scala: Implicit Converters

September 22nd, 2008 No comments

No post anterior entre outras coisas, comentei de implicit arguments, agora vou comentar um pouco de implicit converters.

Implicit Converters

Outra funcionalidade para os implicits são os conversores implicitos. Essa funcionalidade permite adicionarmos características super dinamicas mas sem deixar que fiquemos com a sensação de não sabermos de onde vem as coisas. O que o compilador do Scala faz é olhar se estamos tentando usar um objeto de um determinado tipo como se fosse de um outro tipo, e então procura uma função que converta um objeto do primeiro tipo para o último.

Por exemplo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Vaca {
    def mugir() = "muuuuuuu"
}
//...
class Cachorro {
    def latir() = "au!"
}
 
//...
 
var mimosa = new Vaca
 
def passearComCachorro(toto: Cachorro) = {
    toto.latir()
}
 
passearComCachorro(mimosa) // isso vai dar erro?!
 
//a não ser que eu tenha algo assim
class Vacachorro(vaca: Vaca) extends Cachorro {
    override def latir() = "Antes eu fazia " + vaca.mugir() + ", mas agora eu sei latir!"
}
 
//e esse método converte
implicit def funcaoQueConverteVacaEmCachorro(vaca: Vaca) = new Vacachorro(vaca)

Esse código parece bem esquisito mas funciona. Eu dei um exemplo bem esdrúxulo apenas para mostrar a possibilidade que o Scala dá. Obviamente os conversores geralmente são usados para converter um tipo numérico em outro, ou coisas do genero, mas dei um exemplo pouco convencional propositalmente.
Na linha 17 o compilador do Scala procura por uma função que receba uma Vaca e devolva um Cachorro, porque é o tipo de conversão que ele percebe que precisa acontecer. Entao o compilador faz algo assim:

passearComCachorro(funcaoQueConverteVacaEmCachorro(mimosa))

Agora caso o compilador não encontrasse nenhuma, ou mais de uma função desse tipo, ele daria erro de compilação.
Mas fora converter ao chamar uma função, o Scala permite também fazer isso:

mimosa.latir()

Que em tempo de compilação o Scala vai transformar em

funcaoQueConverteVacaEmCachorro(mimosa).latir()

Novamente gostaria de frisar que esse exemplo é mais didático do que funcional. Na prática poderíamos criar um conversor assim

1
2
3
implicit def conversorQualquer(objeto: Any) = new {
        def latir() = "Um objeto qualquer agora passou a latir"
}

Ou então poderíamos ter esses conversores em alguma outra classe e usar “static imports” para importar esses conversores para nosso código.

Lembrando sempre que se se não houver, ou haver mais de um conversor compatível, o compilador vai dar erro de compilação.

Conversores implicitos dão a mesma facilidade de “open classes” com a vantagem que essa conversão só terá efeito no trecho de código onde a função de conversão está visível. Não acontece de adicionarmos uma função em um objeto num canto do sistema e a mesma estar visível em outro, o que é uma desvantagem em potencial das open classes.

Esses conversores são usados muitas vezes pela pelo próprio Scala. Vejam por exemplo a documentação da classe Int onde é dito que existe um conversor implícito que converte uma instancia de Int para RichInt.

Num próximo post vou comentar sobre mixins classes com Scala.

Categories: Scala Tags: ,

Scalando, parte 2

September 19th, 2008 No comments

No post anterior a gente viu algumas coisas de Scala de uma forma mais solta, para irmos acostumando com a inguagem. A partir deste post vou tentar mostrar algumas coisas mais específicas.

Functions

Em Scala, uma função é “first-class value”, isso que dizer que assim como qualquer outro valor elas podem ser passadas como parametro para outras funções e serem valores de retorno de funções.

object Main extends Application {
    def percorreLista[T](lista:List[T], funcao:(T) => Unit)= {
    for (elemento <- lista) {
      funcao(elemento)
    }
  }
 
  def imprimeElemento[T](elemento:T) = {
    println(elemento)
  }
 
  percorreLista(List(2,3,4,5), imprimeElemento)
}

Aqui definimos uma função chamada percorreLista que faz o que o nome diz e para cada elemento ela invoca uma outra função passada como parametro, no caso a função imprimeElemento. Reparem na linha 2 a definição dos tipos dos parametros. O primeiro é uma lista do tipo T, nada demais. O segunda parametro é um pouco mais interessante. Definimos uma variável chamada funcao que é do tipo “função void que recebe T como parametro”. Então na linha 12 passamos a função imprimeElemento como parametro para a função percorreLista. A saída desse trecho de código é a seguinte

2
3
4
5

Da mesma forma que passamos uma função como parametro, poderíamos retornar uma também. Mas para não alongar muito isso fica como tarefinha :D

O caracter _

Uma das coisas que eu mais estranhei nos códigos feitos com Scala, foi a constante aparição de um “_”, geralmente sendo passado como argumentos de funções. Isso causou mais estranheza pois em Java quase não temos esse caracter. Mas vamos a mais um exemplo.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
object Main extends Application {
 
    def escreveString(s:String) = {
    println("Escrevendo->"+s)
  }
 
  def somatorio(i:Int*) = {
    "Soma=" + i.reduceLeft((a: Int, b: Int) => b + a) // executa mas nao faz efeito
    "Soma=" + i.reduceLeft((a,b) => a + b) //executa mas nao faz efeito
    "Soma=" + i.reduceLeft(_+_) //executa mas nao faz efeito
    "Soma=" + i.foldLeft(0)(_+_) //executa mas nao faz efeito
    "Soma=" + (0 /: i)(_+_) // executa e retorna
  }
 
  escreveString(somatorio(1,4,6))
}

Saída

Escrevendo->Soma=11

Como sempre eu já apriveitei o mesmo exemplo para mostrar várias coisas. Só vou falar da função domatorio, já que o resto só usa o que nós já vimos antes. A começar pelo parametro, é assim que definimos varargs em Scala. Então temos uma função que recebe uma lista de Int de tamanho variável. Na prática i é do tipo Seq[Int]. update: A partir varsão 2.8 varargs são do tipo scala.collection.mutable.WrappedArray, nesse caso mais especificamente do tipo scala.collection.mutable.WrappedArray$ofInt.

No corpo dessa função eu coloquei de formas diferentes a mesma coisa, porém parti do mais legível para o mais ilegível. As funções reduceLeft e foldLeft trabalham de formas diferentes, mas nesse caso o resultado é o mesmo. Olhando o exemplo da documentação fica fácil entender como elas funcionam.

Como eu já disse antes, o retorno de uma função é sua última instrução. Nesse exemplo da função somatório, apenas a linha 12 retorna, as demais efetuam a mesma operação mas o valor é perdido por ninguem usar. A idéia é mostrar as formas diferentes de fazer a mesma coisa, e assim facilitar o entendimento do uso do caracter “_”.

Da linha 8 até a linha 10 usamos a função reduceLeft, e de cima para baixo eu fui reduzindo a especifidade dos parametros. Na linha 8 eu deixei totamente especificado e inverti o ordem ao somar a e b. Não que isso faça diferença no resultado, mas só para exemplificar que a vantagem de se ter as duas variáveis explicitas é poder saber “quem é quem”. Na linha seguinte eu não informei mais o tipo das variáveis a e b pois o Scala consegue perceber isso pra mim, mas continuo podendo brincar com a ordem os parametros pois ainda sei quem é quem.

A partir da linha 10 eu comecei a usar o caracter “_”. Veja que da linha 9 para a 10, olhando o código nós conseguimos perceber que não é tão útil ter as duas variáveis ali pois simplesmente repassamos elas para a expressao a + b. Olhando dessa forma a sintexe da linha 10 parece fazer mais sentido, pois nessa linha nós dizemos que tanto faz quais são as variáveis, eu só quero somá-las. O problema de usar isso é que a legibilidade do código começa a piorar um pouco.

Agora vamos ver as linhas 11 e 12. Olhando a documentação da função foldLeft vemos que ela recebe mais um parametro que o ponto de partida. Como estamos trabalhando com uma soma, passamos o 0, se fosse uma ultiplicação passaríamos 1, pois queremos que esse parametro não influencie no resultado. Mas apesar de mudarmos de função a sintaxe usada las linhas 10 e 11 são equivalentes. Agora na linha 12 bagunçamos de vez e usamos /:, um alias para a função foldLeft. Novamente o problema do código dessa linha é que fica muito ilegível. Olhando para ela, a sintaxe das linhas 10 e 11 até parece mais simpática :D

Múltiplas listas de argumento

Em Scala uma função, diferente do que acontece no Java, pode ter diversas listas de argumentos

object Main extends Application {
    def imprimeStrings(s:String)(s2:String) = {
        println(s2 + "-->" + s)
    }
    imprimeStrings("A", "B")

Saída

B-->A

Pode parecer meio estranho, mas essa sintaxe permite que façamos algo interessante com esse último parametro. A seguir continuamos o código de cima.

    def funcaoQueDevolveString(i:Int) = {
        "Número:" + i
    }
    imprimeStrings("A") {
        funcaoQueDevolveString(5)
    }
}

Saída

A-->Número:5

A funcaoQueDevolveString é só para ilustrar que dentro do bloco de código da chamada da função imprimeStrings eu posso fazer qualquer coisa, desde que o retorno desse corpo seja do tipo do parametro que ele substitui.

Implicit parameters

Outra aplicação para mais de uma lista de argumentos é quando queremos ter uma lista de argumentos implicita. Vamos ao exemplo.

object Main2 extends Application {
    implicit var user = "Gilliard"
 
    def executaOperacao(f:()=>Unit)(implicit usuario:String) = {
        println(usuario + " vai executar uma operação")
        f()
        println(usuario + " executou uma operação")
    }
 
    def operacao() = println("Executando operação")
 
    executaOperacao(operacao)
}

Saída

Gilliard vai executar uma operação
Executando operação
Gilliard executou uma operação

Como isso funciona? Definimos uma função executaOperacao que recebe como primeiro parametro uma função. Até aqui nada de novo. Porém definimos uma segunda lista de argumentos com implicit. A palavra reservada implicit deve ser aplicada no início de uma lista de argumentos, e afeta todos os argumentos dessa lista. Além disso essa lista de argumentos deve ser a última. Então caso eu queira ter argumentos “normais” e argumentos implicitos, eu precisaria ter duas listas de argumentos como no exemplo.

Quando o compilador do Scala encontra uma função com parametros implicitos, ele busca por objetos implicitos que sejam compatíveis com esses parametros. Caso encontre, como no nosso exemplo, tudo bem, agora se não houver nenhum objeto implicito compatível teremos um erro de compilação. Mas isso é bem flexível, se eu não tivesse um objeto implícito e quisesse invocar uma função com parametros implícitos é só eu passar explicitamente esses parametros. Um parametro implícito se torna opcional, mas não é proibido colocar um valor explícito. Agora se mais de um valor explícito compatível estiver disponível o compilador não vai tentar adivinhar qual usar, vai dar erro de compilação.

No próximo post vou falar de implicit converters, que na minha opinião é uma das coisas mais bacanas e simples de usar do Scala. Aí sim a gente começa a ver o poder de uma linguagem escalável, com muito dinamismo mas sem deixar que “vire zona”.

Categories: Scala Tags: , ,

Olá Scala

September 16th, 2008 1 comment

Estive presente no JustJava2008 e aos poucos vou postar aqui algumas das coisas interessantes que vi. Para começar, vou falar um pouco da linguagem Scala, que roda na JVM e que está ficando cada vez mais conhecida.

Há algum tempo, pesquisando sobre Groovy, encontrei este post que fala sobre Scala. Depois disso me interessei e pesquisei um pouquinho sobre Scala mas não evoluí muito no assunto.Porém depois da apresentação feita pelo Michael Nascimento no JJ08, me animei a brincar com Scala mais um pouco e, agora que já tinha um norte, ficou muito mais fácil conseguir fazer algumas coisas com essa linguagem.

Primeiramente gostaria de dizer que não sou um expert em Scala, só estou compartilhando o que tenho aprendido nos últimos dias. Como já disse, esse post foi basicamente inspirado na apresentação do Mr. M no JJ, e assim que as apresentações estiverem disponíveis vou colocar um link aqui. Outras fontes para esse artigo (e os próximos) é a série Roundup: Scala for Java Refugees, além da própria documentação do Scala.

Scala é um “mix” de linguagem OO e linguagem funcional. Em Scala tudo é objeto, não há primitivos, mas isso a gente ve mais pra frente. O nome Scala vem de “scalable language”. A idéia foi projetar uma linguagem que service bem para trabalhos simples como um pequeno script, até o desenvolvimento de grandes aplicações como fazemos hoje em Java com a “segurança de uma linguagem fortemente tipada”. Hoje em dia se fala muito sobre linguagens dinamicas que rodam na JVM, mas apesar de não parecer (pois olhando o código realmente as vezes não parece), Scala é fortemente tipada assim como Java. A diferença é que pelo fato do Scala usar de forma muito eficiente a inferencia de tipos, acabamos nao tendo aquela sintaxe carregada do Java onde temos que dizer o tipo em todos os lugares e ainda algumas vezes de forma repetida.

Entes de continuar, só para convencionar (mas não quero gerar polemica), chamei de dinamica uma linguagem não tipada.

Para os exemplos, eu usei o plugin do eclipse, mas voces podem ver os plugins disponíveis e usar sua IDE preferida.

Agora um exemplo das diferenças na hora da tipagem

List<String> lista = new ArrayList<String>();

em Java temos que informar duas vezes que estaremos trabalhando com uma List que guarda Strings.

var lista = List("A", "B")
 
//ou para ficar mais parecido com Java...
 
var lista = new ArrayBuffer[String]

Note que nao foi necessário delarar a variável lista como uma coleção de Strings, isso porque o compilador do Scala, assim como nós, ao ler essa linha percebe que a lista referencia uma coleção de Strings. E se eu tentar adicionar qualquer outra coisa que não seja uma String vou ter um erro de compilação. Além disso como Scala não nos obriga a usar ‘;’ (ponto e vírgula) no final das intruções. Então olhando um código sem definições de tipos em muitos casos, e sem ‘;’, às vezes da a impressão que estamos trabalhando com uma “linguagem dinamica” como Groovy por exemplo, já que tem o “estilão” Java de nomearmos as coisas.

Para rodar um código Scala podemos começar de tres formas:

1 – script:

scala> println("Olá mundo!")
Olá mundo!

2 – extendendo a “classe” Application (mais pra frente explico melhor porque coloquei classe entre aspas, mas basicamente é porque Application não é de um tipo Java como class ou interface)

object Main extends Application {
    println("Olá mundo!")
}

3 – ou ainda usando o já conhecido método main

object Main2 {
    def main(args:Array[String]) = {
        println("Olá mundo!")
    }
}

Com esses exemplos ja podemos perceber muitas diferenças em relação ao Java. Talvez a primeira coisa seja o object antes de Main e Main2. Em Java não temos como definir diretamente um object, apenas podemos declarar class e interface. Mas object nada mais é do que uma forma que a própria linguagem nós de definirmos um singleton. Na prática, todos os métodos de um object são acessíveis como métodos estáticos, mas internamente a execução é delegada para um singleton dessa “classe”. Por isso mesmo no exemplo 3 não precisamos definir o método main como estático.

Outra coisa que percebemos é que primeiro declaramos a variável, e depois (se for necessário) informamos o tipo. Isso não tem nada demais mas para quem está acostumado com Java como eu vai querer declarar “String s” algumas vezes antes de acostumar com “s : String” :D

Outra coisa que pode ter passado batido no exemplo 2 é que o println está no corpo do nosso objeto, sem nenhum método em volta dele. Isso acontece porque Application tem um método main que nesse caso serve apenas para podermos executar nossa Main, mas na verdade quem executa o println da linha 2 do segundo exemplo é o contrutor do nosso objeto. Vamos a outro exemplo para ficar mais claro.

object Main3 {
    println("antes")
    def main(args:Array[String]) = {
        println("durante")
    }
    println("depois")
}

A saída do código acima é

antes
depois
durante

Isso se deve ao fato de em Scala, o contrutor padrão de um objeto ser o corpo da classe (obviamente declaracoes de métodos não entram aqui). É como a inicialização estatica em java, que executa antes do contrutor, a diferença é que aqui o que seria essa inicliazação estatica é o contrutor. Mas vamos entrar mais a fundo nisso depois.

Vamos a mais um exemplo

object Main4 {
    def main(args:Array[String]) = {
        def éPar(i : Int) = {
            i % 2 == 0
        }
        println( éPar(10) )
    }
}

A saída do trecho de código acima é true. Mas nesse exemplo podemos ver muitas outas coisas interessantes. Primeiramente dentro de um método podemos declarar outro método (além de diversas outras coisas, inclusive fazer imports visíveis dó naquele escopo). Em Java também podemos fazer algo parecido, usando uma classe interna anonima. Inclusive é isso que o Scala vai gerar no bytecode, mas isso já é outra história.
Só abrindo um parenteses, eu falo muito em método pois sou um programador Java, falando pra outros programadores Java, mas muita gente pode achar ruim pois talvez o correto seria eu falar function, lembrando que Scala é uma linguagem funcional. Fecha parenteses :D
Também não precisamos declarar o tipo de retorno do nosso método pois o Scala consegue inferir isso pra gente. Assim como eu posso olhar e perceber que isso vai retornar um Boolean, o compilador do Scala também pode.

Essa delcaracao seria o mesmo de

def éPar(i : Int) : Boolean = { ... }

Assim como na definição da main eu poderia colocar asssim

def main(args:Array[String]) : Unit = { ... }

Em Scala, o correspondente para o void do Java é Unit.

Outra coisa que não precisamos colocar explicitamente é o return, poi o Scala considera como o retorno de um método a sua última linha. No entanto em alguns casos, como no uso de recursão ou quando descobrimos antecipadamente o que deve ser retornado, acabamos precisando explicitar o return, aí nesse caso precisamos deixar explicito também o tipo de retorno do método.

Como a maioria das linguagens de script, Scala permite que chamemos um método de uma forma diferente, sem o ‘.’ e os “(…)” o que possibilita que possamos usar

i % 2 == 0

em vez de usar o equivalente

(i.%(2)).==(0)

Isso mesmo, pode parecer meio estranho mas isso é assim. Em Scala não existem primitivos, e também não existe sobrecarga de operadores (o que seria dos professores de POO com C++ que só sabiam dar isso de matéria se o Scala virasse padrão nessas instituições hein….). O que ocorre é que em Scala “%” e “==” são nomes válidos para métodos. Assim como praticamente qualquer coisa que podemos escrever como <<, >;=, +=, *, etc.

Esse primeiro post foi mais para dar uma idéia de como começar a brincar com Scala, mas nos próximos vou entrar em mais aspectos da linguagem como objetos imutáveis, traits, closures, etc.

Qualquer gafe minha voces postem um comentário que eu corrijo ok? Até o próximo.

Categories: Scala Tags: , , ,