DevMedia - asp.net, Java, Delphi, SQL e web Design, tudo em um só lugar!
Bem vindo a DevMedia!
LOGIN:     SENHA:
 
 

  Este é um post disponível para assinantes MVP
Este post também está disponível para assinantes da Java Magazine DIGITAL ou para quem possui Créditos DevMedia.  Clique aqui para saber mais!


Compilação Dinâmica no Java 6 - Revista Java Magazine 94

Este artigo aborda a Compiler API, que possibilita compilar classes de uma aplicação durante a sua execução. Um framework que gera classes DAO (Data Access Object) é criado para exemplificar o uso da API, bem como uma aplicação que utiliza este






Praticamente toda aplicação Java desenvolvida segue o mesmo processo até ser executada. Tudo começa com a escrita dos códigos-fonte das classes, que posteriormente são compilados para uma linguagem intermediária chamada bytecode. Depois, no momento em que a aplicação começa a ser executada, a JVM faz o carregamento e interpretação destas classes compiladas, a fim de que tudo funcione de acordo com o que foi implementado.

Embora este seja o processo mais comum, ele não é o único. A partir do Java 6 foi introduzida na linguagem a Compiler API, que possibilita uma variação no processo descrito anteriormente. Com esta API, classes da aplicação podem ser definidas, compiladas e terem seus bytecodes carregados pela JVM enquanto a aplicação é executada. Na prática, isto significa que estas classes não existem durante a compilação.

A apesar de a Compiler API ser relativamente recente (a partir da versão 6 do Java), a ideia de gerar classes em tempo de execução não é nova. Existem diversos frameworks e APIs que tiram proveito deste recurso. Para que isso fosse possível há alguns anos, eles utilizavam bibliotecas desenvolvidas por terceiros como o CGLIB e o ASM, as quais permitem a manipulação direta de bytecode; ou o Apache Commons JCI, que é uma interface para um compilador Java já existente, responsável por gerar as classes. Para mais informações sobre estas APIs, consulte a seção de Links.

Um exemplo bastante claro de utilização deste recurso vem dos JSPs, que são utilizados para renderizar páginas web dinâmicas para os usuários. Quando um JSP é requisitado pela primeira vez, o servidor executa um processo de conversão do arquivo JSP para uma classe de Servlet, compila este arquivo e o carrega. Isto possibilita que o desenvolvedor faça a programação da página como se ela fosse um JSP, mas na hora da execução a página dinâmica é gerada por um Servlet. A vantagem disso é que a facilidade de implementar a estrutura de uma página web dinâmica em JSP é muito maior.

Outro framework que utiliza a geração dinâmica de classes é o Hibernate. Para que ele possa fazer o gerenciamento de persistência das entidades, o Hibernate precisa criar classes de proxy, as quais agem como classes intermediárias no momento em que o framework precisa acessar as entidades reais, criadas pelo desenvolvedor. Os proxies são gerados em tempo de execução e escondem do programador a complexidade deste processo, uma vez que estas classes não existem antes do código ser executado.

Por fim, outro exemplo de API que utiliza este recurso é o RMI (Remote Method Invocation). Ele possibilita que o usuário faça chamadas de métodos em objetos que podem estar localizados em outro computador da rede. Mas para quem faz a chamada, toda esta complexidade da invocação remota é transparente, uma vez que o código é escrito como se ela fosse local (dentro da própria JVM). Isto só é possível devido a um componente chamado stub, que é uma espécie de objeto local que representa o objeto remoto. É dele a responsabilidade de fazer com que a requisição ao objeto real seja feita via rede e também de receber o retorno da invocação. Para que o desenvolvedor não se preocupe com todos estes detalhes, os stubs necessários são gerados durante a execução da aplicação.

Com base nos exemplos citados, é possível perceber que a compilação dinâmica tem os seus benefícios. A geração de código em tempo de execução pode ser muito útil no desenvolvimento de frameworks que buscam reduzir a complexidade de escrita de código por parte dos desenvolvedores. Pode também ser utilizada para gerar código Java a partir de uma linguagem qualquer, que poderia ser específica de um domínio ou aplicação. E ferramentas que automatizam a geração de código também podem se beneficiar deste recurso, podendo gerar classes a partir de templates pré-definidos.

Este artigo é dividido em três partes. Na primeira, o processo de compilação dinâmica com a Compiler API será explicado em detalhes. Na segunda, um framework que gera classes DAO (Data Access Object) será proposto, com o objetivo de mostrar um exemplo prático da compilação em tempo de execução. E na terceira e última parte, a utilização deste framework será demonstrada através da criação da camada DAO de uma aplicação fictícia, cuja função é gerenciar infrações de trânsito. A proposta desta divisão é mostrar não só a teoria, mas também os benefícios práticos da Compiler API.

A Java Compiler API

Como já foi mencionado, existem diversas formas de gerar classes em tempo de execução no Java. Antes da versão 6, nenhuma delas era padrão da linguagem e sempre houve a dependência de bibliotecas criadas por terceiros.

Com o intuito de padronizar este recurso e torná-lo nativo do Java, foi criada a JSR 199, que define a Compiler API. Implementada a partir do Java 6 e localizada no pacote javax.tools, ela tornou possível compilar classes durante a execução da aplicação e permitir que elas sejam carregadas pela JVM para serem utilizadas. Com esta API, os desenvolvedores não precisam mais recorrer a bibliotecas externas, que podem não acompanhar os lançamentos de novas versões da linguagem. Além disso, a Compiler API é capaz de gerar classes a partir de códigos-fonte armazenados em qualquer lugar (como arquivos ou até strings), e em nenhum momento o desenvolvedor precisa se envolver diretamente com o bytecode gerado. Isto reduz significativamente a complexidade de implementação.

A utilização desta API exige a criação de algumas classes, o que resulta em um volume considerável de código. Por este motivo, o ideal é encapsular toda a implementação necessária, de forma que ela possa ser reaproveitada em diversas aplicações da forma mais simples possível. Ao final desta primeira parte do artigo, você terá esta biblioteca criada e pronta para ser utilizada em diversos projetos.

Independente da complexidade envolvida no processo de compilação dinâmica, a essência deste recurso é simples: a partir de um código-fonte é gerada uma classe compilada. Com base nisso, a primeira classe importante que será criada é denominada JavaCodeCompiler. Ela possui apenas o método compile(), que recebe os nomes do pacote e da classe que será compilada e o código-fonte. O seu retorno é um objeto Class, que representa a classe já compilada. Outro detalhe é que JavaCodeCompiler pode ser parametrizada, pois suporta o uso de generics. Isto permite definir a classe de retorno do método.

Definir a classe retornada pelo método compile() pode parecer estranho à primeira vista, já que não é possível referenciar no código-fonte uma classe que só vai existir quando a aplicação for iniciada. No entanto, é bastante comum que as classes compiladas dinamicamente sejam subclasses ou implementações de interfaces. Neste caso, o tipo parametrizado especificado é o mais genérico, que já é conhecido no momento da compilação.

Veja um exemplo de utilização da classe JavaCodeCompiler na "



ATENÇÃO! A exibição deste artigo foi interrompida.


  Este é um post disponível para assinantes MVP
Este post também está disponível para assinantes da Java Magazine DIGITAL ou para quem possui Créditos DevMedia.  Clique aqui para saber mais!






    11 COMENTÁRIOS

[Fechar]

Este post é fechado - você precisa ter acesso ao post para incluir um comentário.



Paulo Júnior
As listagens 14, 15 e 16 estão sem os links
[há +1 mês] - Responder

 

Devmedia - Equipe De Moderacao
Paulo, o problema foi resolvido!

Atenciosamente,

Equipe Devmedia.
[há +1 mês] - Responder
 

Mauricio Nunes
Eu estou tentando compilar o codigo da listagem um, mas a classe Compiler não existe dentro do pacode javax.tool conforme digo pelo autor. Onde está essa classe?
[há +1 mês] - Responder

 

[autor] Carlos Eduardo Gusso Tosin
Mauricio,

A classe Compiler fica no pacote java.lang, e não no pacote javax.tool. O arquivo tools.jar deve estar no classpath para que a compilação dinâmica funciona, mas a classe Compiler não faz parte deste JAR.

Abraço!
[há +1 mês] - Responder
 

Wesley Yamazack
Olá Mauricio, entramos em contato com o autor para que o mesmo possa lhe ajudar. Obrigado pelo comentário.

Um abraço
[há +1 mês] - Responder
 

Mauricio Nunes
Oi Carlos, tudo bem?
Me desculpa pela dificuldade que estou tendo, mas não consigo compilar a classe da listagem 1.
Essa classe ela existe no pacote java.lang, mas me da erro de compilação. Por um acaso eu preciso de mais algum jar no meu classpath? Do jeito que está o código na listagem, não funciona.
[há +1 mês] - Responder
 

[autor] Carlos Eduardo Gusso Tosin
Mauricio,

Certifique-se de que você está usando a versão 6 do Java. Em versões anteriores o exemplo não vai funcionar. Se ainda estiver com dificuldades me mostre os erros que estão ocorrendo.

Abraço
[há +1 mês] - Responder
 

Mauricio Nunes
Oi Carlos, tudo bem?
Certeza que estou utilizando o java 6. Quando tento compilar o eclipse, mostra a linha vermelha em cima da classe Compiler com a seguinte mensagem:

Multiple markers at this line
- The type Compiler is not generic; it cannot be parameterized with arguments
- The type Compiler is not generic; it cannot be parameterized with arguments

Essa classe Compiler, eu não consigo dar um new nela.

Abraços
[há +1 mês] - Responder
 

[autor] Carlos Eduardo Gusso Tosin
Mauricio,

Dei uma olhada novamente no código. Vou tentar consertar a informação que passei a você anteriormente :)

Em nenhum momento eu utilizo a classe Compiler diretamente. A classe usada é a JavaCompiler, do pacote javax.tools.

Certifique-se de que na sua IDE (ex: Eclipse, Netbeans) você está utilizando algum JDK instalado no seu computador associado ao seu projeto, e não um JRE. O motivo é que o JRE não tem o arquivo tools.jar, que é onde a classe está localizada. Se você tiver dificuldades em fazer esta configuração na IDE, você pode simplesmente adicionar o arquivo tools.jar ao classpath (você encontra este arquivo na pasta do JDK), que funciona também.

Abraço
[há +1 mês] - Responder
 

Mauricio Nunes
Carlos, tudo bem?
Desisto cara. Adicionei a tools.jar e mesmo assim não funciona o código da listagem 1.
[há +1 mês] - Responder
 

[autor] Carlos Eduardo Gusso Tosin
Mauricio,

Você pode mostrar pra mim o trecho de código onde está ocorrendo o problema? Pelo erro que você me apresentou parece que você está trabalhando com a classe Compiler do Java diretamente, mas na verdade esta classe nem é usada.

Outra coisa: que IDE você está usando? Eclipse ou Netbeans?

Vamos tentar descobrir esse problema aí :)
[há +1 mês] - Responder
 



Publicidade
Autor
Carlos Eduardo Gusso Tosin

É Mestre em Informática pela PUC-PR. Trabalha com Java há 8 anos, sendo 5 deles no desenvolvimento de sistemas para a IBM dos EUA. Também é instrutor oficial dos cursos de Java da Softblue (www.softblue.com.br). Possui as certificações SCJP, SCJD, SCWCD, SCBCD e SCEA.


Space do autor
Estatísticas
Favorito:
Comentários:
Feedback:
Utilidade:
0   0
[Fechar]

Você precisa estar logado para dar um feedback.

Clique aqui para efetuar o login
[Fechar]


Este post está fechado. Saiba mais sobre a assinatura MVP!
web-03
DevMedia  |  Anuncie  |  Fale conosco
Hospedagem web por Porta 80 Web Hosting
2012 - Todos os Direitos Reservados a web-03