Nesse post vou escrever um pouco sobre o Compilador do Google Web Toolkit, qual é o seu papel no kit, além de algumas dicas para o dia-a-dia no desenvolvimento com a tecnologia.
Como exemplo vou usar um novo Projeto Web no Eclipse criado a partir do Google Plugin para desenvolvimento GWT e/ou App Engine, acesse aqui mais informações e download.
Depois de instalar o plugin, dentro do Eclipse siga a sequência para criar o projeto:
New - Others - Google - Web Application Project - Defina o nome do projeto e a estrutura raiz de pacotes - Finish.
Vou adotar como nome do projeto appGWT e pacote br.com.globalcode. O plugin gera uma aplicativo pronto que permite ao usuário preencher um campo e realizar o envio ao servidor de forma assíncrona (Ajax), quando o servidor responde um Dialog é apresentado com a mensagem de retorno. Para testar a aplicação é só executar o projeto com a opção Wep Application. Veja:
O GWT, como já foi comentado, adota um conceito bem interessante para construir sofisticadas soluções web (RIA) usando Java nas camadas Client/View (Browser) e Server. Repare na estrutura de nosso aplicativo exemplo, as classes dentro do pacote br.com.globalcode.client são transformadas em JavaScript, enquanto dentro de br.com.globalcode.server o conteúdo permanece em Java rodando dentro do web-server.
Essa transformação é possível através do Compilador do GWT, que diferente do javac, transforma/traduz o código da camada Client escrito em Java para JavaScript. Além dessa transformação o GWT também otimiza o código gerado, removendo método que nunca é usado ou que sempre retorna o mesmo valor.
Para analisarmos um pouco de como o Compilador se comporta, podemos escrever o seguinte código na classe AppGWT.java:
/**
* Entry point classes define onModuleLoad()
.
*/
public class AppGWT implements EntryPoint {
...
public String getTextoPadrao() { return "Testando GWT"; } public void onModuleLoad() { final Button sendButton = new Button("Send"); final TextBox nameField = new TextBox(); nameField.setText(getTextoPadrao()); ... } ... }
AppGWT.java é o ponto de entrada (EntryPoint) da aplicação, ou seja, o código executado quando o usuário acessa a página.
Agora é só compilar! Por padrão o código JavaScript gerado é compactado e ofuscado, inviabilizando a analise. Durante o desenvolvimento pode ser interessante ler o conteúdo JavaScript, por isso é possível indicar ao compilador que a geração do código deve ser em um formato legível. [Importante: Esse recurso deve ser usado somente durante o desenvolvimento]
Com botão direito do mouse sob o nome do projeto selecione Google - GWT Compile - modifique o Output Style de Obfuscated para Pretty - Clique em Compile. Veja:
O conteúdo gerado pelo compilador GWT fica dentro da pasta /war/appgwt . Após o compilador encerrar a execução, atualize o conteúdo da pasta war e verifique os arquivos gerados. O código JavaScript de startup fica no arquivo appgwt.nocache.js, comum a todos os Navegadores ("userAgent"). O GWT também gera alguns arquivos html - extensão .cache.html - com o JavaScript gerado a partir do Java, cada arquivo com conteúdo suportado por um Navegador .
No arquivo appgwt.nocache.js temos o seguinte trecho:
... if (!strongName) { try { unflattenKeylistIntoAnswers(['safari'], '2B012280038ECE4F899173361F1A5AEF.cache.html'); unflattenKeylistIntoAnswers(['opera'], '16C2FF59D1A299AD6194A71D9D33861F.cache.html'); unflattenKeylistIntoAnswers(['gecko'], '578F90996AD9305BA987E10AF37C8645.cache.html'); unflattenKeylistIntoAnswers(['gecko1_8'], 'B6DDD0AD31CB650064F7B6DC35EBE762.cache.html'); unflattenKeylistIntoAnswers(['ie6'], 'C46730CF80EA3F49ED2C299E016471DF.cache.html'); strongName = answers[computePropValue('user.agent')]; } catch (e) { return; } } ...
Nesse pedaço é feito o mapeamento do Navegador e o seu arquivo .cache.html correspondente. Todo esse mecanismo é chamado de Deffered Binding, com ele o GWT resolve as incompatibilidades de JavaScript com hacks e workarounds (jeito mais elegante de dizer gambiarra) para cada navegador. O Deferred Binding seria uma alternativa para Reflection suportada no Java, o detalhe que esse vinculo ou ligação é feito estaticamente, já que o ambiente JavaScript não suporta Dynamic Class Loading.
Uma curiosidade, o GWT nomeia os arquivos .cache.html usando um MD5 sum de acordo com o conteúdo Java, no caso do Firefox (gecko1_8) o arquivo é B6DDD0AD31CB650064F7B6DC35EBE7 62.cache.html. Abra esse arquivo e veja o seguinte trecho:
... var _; function equals_2(other){ return this === (other == null?null:other); } function hashCode_4(){ return this.$H || (this.$H = ++sNextHashId); } function Object_0(){ } _ = Object_0.prototype = {}; _.equals$ = equals_2; _.hashCode$ = hashCode_4; _.typeMarker$ = nullMethod; _.typeId$ = 1; function $AppGWT(this$static){ this$static.greetingService = $GreetingService_Proxy(new GreetingService_Proxy()); return this$static; } function $onModuleLoad(this$static){ var closeButton, dialogBox, dialogVPanel, handler, nameField, sendButton, serverResponseLabel, textToServerLabel; sendButton = $Button_0(new Button(), 'Send'); nameField = $TextBox(new TextBox()); nameField.element['value'] = 'Testando GWT !' != null?'Testando GWT !':''; setStyleName(sendButton.element, 'sendButton', true); $add(get_0('nameFieldContainer'), nameField); $add(get_0('sendButtonContainer'), sendButton); $setFocus(nameField, true); $selectAll(nameField); ... } ...
Essa é a tradução do método onModuleLoad() da classe AppGWT, mas repare que o compilador não considerou o método getTextoPadrao(), passando o conteúdo 'Testando GWT' na property do input. Se você achou esse código JavaScript complexo e dificil compile novamente a aplicação no estilo Obfuscated e experimente visualizar os fontes! Ainda bem que no dia-a-dia não precisamos nos preocupar com isso, a proposta é justamente deixar o JavaScript por conta do GWT.
Um outro detalhe da compilação é que o GWT organiza código Java no modelo AST (Abstract Syntax Tree), aonde cada elemento sintático do código é um objeto (nó) Java na árvore, Podemos fazer uma breve comparação desse modelo de organização ao DOM (Document Object Model).
O processo de compilação ainda é caro por isso o GWT disponibiliza o Hosted Mode, que permite economizar um bom tempo além deixar a construção e manutenção mais produtiva. O Hosted Mode emula código Java como JavaScript sem realizar a compilação.
Durante o desenvolvimento uma dica que pode agilizar a compilação seria gerar JavaScript para um navegador, o Firefox por exemplo. Podemos indicar isso ao GWT com a seguinte linha no arquivo de configurações do projeto, AppGWT.gwt.xml:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 1.7.0//EN" "http://google-web-toolkit.googlecode.com/svn/tags/1.7.0/distro-source/core/src/gwt-module.dtd"> <module rename-to='appgwt'> ... <define-property name="user.agent" values="gecko1_8" /> ... </module>
A Globalcode disponibiliza um mini-curso sobre GWT, o MC56, não perca!
Eder Magalhães
http://twitter.com/edermag
http://www.yaw.com.br
Eder Magalhães
http://twitter.com/edermag
http://www.yaw.com.br
Comentários
Estou até assustado. Hahahaha.
Acho q nao entendi a coisa mas me parece q o codigo continua aberto e nao compilado.
Eu escondia os jss codificando mais uns 4 a 5 um chamando o outro.
Adoro Javascript e nao entendo por q ainda nao hesiste compilador pra ele. Buáááá
Tenho progs incríveis em JS.
Abraços, fui.
Paschoal, Vila Velha, Esp. Santo.