Java 6 compilará fonte dentro de uma aplicação pronta

21 respostas
Luca

Olá

O Java 6 virá com a nova JSR-199 com as seguintes utilidades:

  • API para invocar o compilador
  • API para obter diagnósticos em forma estruturada
  • plugin API para permitir compilação para a memória ou compilação a partir do que está armazenado na memória em uma String e também de outras locações

Em pseudo código um exemplo poderia ser assim:

Reader rdr =new StringReader("class Foo { int max(int i, int j) { if (...) ... } }");
javac.compile(rdr);

Porém não haverá classe javac e tudo foi feito de modo mais genérico. A receita de bolo será a seguinte:

  1. Criar um objeto [color=darkblue]JavaCompiler[/color] de um [color=darkblue]ToolProvider[/color]

  2. Criar um [color=darkblue]StandardFileManager[/color], que é um gerenciador de Files baseado em java.io.File, correspondente ao objeto anterior

  3. Com o objeto da interface [color=darkblue]StandardFileManager[/color], criar um Iterable que extende [color=darkblue]JavaFileObject[/color] contendo uma ou mais unidades à compilar (*)

  4. Usar o método [color=darkblue]getTask()[/color] (**) do objeto criado em 1. com a interface [color= darkblue]JavaCompiler[/color] para retornar um [color= darkblue]JavaCompiler.CompilationTask[/color] para o qual se chama o método [color=darkblue]call()[/color] que finalmente compila todas as unidades que queremos compilar

(*) “arquivos” fonte.
(**) [color=darkblue]getTask(Writer, JavaFileManager, DiagnosticListener<? super JavaFileObject>, Iterable<String>, Iterable<String>, Iterable<? extends JavaFileObject> )[/color]

Da JSR tirei o seguinte trecho de código:

Files[] files1 = ... ; // input for first compilation task

    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
       
    StandardJavaFileManager fileManager =                                                                                                          
                 compiler.getStandardFileManager(null, null);

    Iterable<? extends JavaFileObject> compilationUnits1 =
                 fileManager.getJavaFileObjectsFromFiles(Arrays.asList(files1));

    compiler.getTask(null, fileManager, null, null, null,
                 compilationUnits1).call();

    fileManager.close();

Na verdade o conjunto de instruções que está na JSR-199 pega 2 grupos de arquivos e compila os 2 reusando o mesmo StandardFileManager para o cache dos arquivos jar.

É possível pegar também os diagnósticos da compilação, logar tudo que está fazendo e compilar um arquivo guardado em uma String extendendo SimpleJavaFileObject. Tudo isto tem exemplo no javadoc da interface JavaCompiler

Tá bom ou querem mais? :lol:

[]s
Luca

21 Respostas

J

Isso já é possivel hoje usando o compilador do Eclipse ou para generalizar o commons-jci.

Eu inclusive já utilizei isso, funciona bem.

brunogamacatao

Sempre existiu em java a classe javac, é só invocar o método main desta classe passando como parâmetros dentre outras coisas o fonte a ser compilado.

J

Sempre não, somente usando o JDK e com o tools.jar no classpath.

Lembre-se que sistemas java no cliente rodam em JRE.

Luca

Olá

  1. Se já existisse antes da forma como passará a existir ninguém perderia tempo fazendo.

  2. Pelo que li no fórum da Sun em uma mensagem antiga que não sei se valerá no momento do lançamento, só será possível usando o JDK, só com o JRE não funcionará.

[]s
Luca

Daniel_Quirino_Olive

Poderia ser um pouquinho mais simples, né?

Compiler c = ToolProvider.getTool(Tools.Compiler);
c.compile(...); // paramêtros: String, File, Reader, InputStream
Luca

Olá

Daniel, da forma que você fez, poderá ser feito pelo usuário criando seus próprios métodos.

O ToolProvider que você manteve permite a escolha do compilador. O uso do conceito de file manager na API é para torná-la genérica pois os fontes podem vir de vários locais, inclusive da memória. O Iterable não é obrigatório, este exemplo compila vários arquivos fontes de uma vez só. E os demais parâmetrs de getTask servem para pegar os diagnósticos, jogar o resultado da compilação para arquivos diferentes, etc.

[]s
Luca

Daniel_Quirino_Olive

Luca:
Olá

Daniel, da forma que você fez, poderá ser feito pelo usuário criando seus próprios métodos. O uso do conceito de file manager na API é para torná-la genérica pois os fontes podem vir de vários locais, inclusive da memória. O Iterable não é obrigatório, este exemplo compila vários arquivos fontes de uma vez só. E os demais parâmetrs de getTask servem para pegar os diagnósticos, jogar o resultado da compilação para arquivos diferentes, etc.

[]s
Luca

Hmmm. Ok. Então acho que ficou legalzinho :slight_smile:

Grinvon

Eu tinha pensando nessas possibilidades a algum tempo, é bem interessante isso, sempre pensei… já pensou se Java pode-se rodar Java dentro dele?

Luca

Olá

E programas que escrevem programas “on the fly”? Quem acha que isto não é novidade está desafiado a usar o compilador do Eclipse (ou do jakarta commons quando a lista de TODOs for um pouco menor) para compilar um Hello World armazenado em uma String e ter diagnósticos e logs.

[]s
Luca

jack_ganzha

Perguntinha boba, dá para compilar trechos de codigos apenas? Por exemplo, quero ver como funciona um metodo tal e não quero escrever toda a tralha de class, main, etc, apenas aquele trecho especifico. Se isso for possivel eu vou achar otimo!

valeuz…

Rubem_Azenha

isso é excelente. Dá para se pensar em simular um gerador de código legal. Da pra brincar de se fazer Java On Rails :slight_smile:

J

Luca:
Olá

E programas que escrevem programas “on the fly”? Quem acha que isto não é novidade está desafiado a usar o compilador do Eclipse (ou do jakarta commons quando a lista de TODOs for um pouco menor) para compilar um Hello World armazenado em uma String e ter diagnósticos e logs.

Entre desafiar e apontar uma solução já existente tem uma grande diferença.

E me desculpe, não é novidade não. Veja o próprio projeto Janino, utilizado pelo Drools para executar código java escrito em uma string (condição da regra).

Dê uma olhada no Commons-jci ou no compilador do Eclipse, se interessar.

Luca

Olá

Janino - projeto levado por uma única pessoa que levou mais de 2 anos até atingir a versão 1.0 e atualmente depois de 5 anos de desenvolvimento ainda falta aceitar várias facilidades do Java e o autor diz que só testou até o j2sdk 1.4.1

Commons-jci - projeto com um único desenvolvedor mais 3 colaboradores, sem versão para download, com fontes apenas disponíveis no subversion e com uma lista de TODOs tão grande que ninguém teria coragem de usar em produção para fazer o mesmo que esta JSR.

Compilador do Eclipse e o javac - se for possível fazer tudo que está na JSR 199 com eles então a turma da Sun que escreveu e testou a API é um bando de tolos sem nada para fazer.

Perguntas:

  1. :arrow: Há muito tempo há vários pacotes de estruturas de dados por aí. Porque a Sun criou e continua expandindo Collections?

  2. :arrow: Há muito tempo estava disponível a API do Doug Lea. Porque a Sun incorporou esta API do Doug Lea no Java 5 e ainda expandiu no Java 6?

  3. :arrow: Há muito tempo que os novos métodos que coletam informações da rede que aparecerão no Java 6 para obter atributos de rede já podiam ser usados de outra maneira. Porque a Sun expandiu os métodos que coletam informações da rede no Java?

Será que a Sun está com enorme capacidade ociosa e fica brincando de colocar mais coisas no Java só para competir com o alemão do Janino?

Este assunto é realmente novo e ainda não saiu em mais do que 2 ou 3 lugares por aí. Você acha que eu perdi tempo a toa estudando a JSR e que não deveria ter trazido para o GUJ porque isto não é nenhuma novidade. Eu achei que seria útil trazer para o GUJ pois para mim a inclusão desta facilidade DENTRO do Java só será possível a partir do Java 6.

[]s
Luca

Luca

Olá

Se eu entendi o que escreveu, não acredito que a JSR tenha sido feita com esta intenção porque isto a gente já faz com testes unitários.

A principal utilidade desta JSR é facilitar a vida de quem escreve IDEs. Ela não foi feita para uso de usuários comuns. Mas alguém mais aventuroso pode criar classes “on the fly” de acordo com parâmetros momentâneos. Na prática isto é arriscado porque depurar eventuais erros pode ser terrível. E manter um sistema assim ficará dependendo de especialistas que geralmente não é uma boa.

[]s
Luca

Sami_Koivu

Luca:

A principal utilidade desta JSR é facilitar a vida de quem escreve IDEs. Ela não foi feita para uso de usuários comuns.

Então, você respondeu a pergunta que eu ainda não fiz. Qual a utilidade de tudo isso? A resposta de IDE parece viável.

A criação “on the fly” de classes me parece menos prático. Deve ser relativamente complicado (difícil não, mas existem vários aspectos chatos) para uma programa criar código java (já que o sintaxe foi criado com pessoas em mente) e o compilador também não foi feito para compilar código criado por uma programa. Assim sendo, eu acho que mesmo que o bytecode não é super simples para obter funcionalidades dinámicas assim, usar alguma coisa como ASM, ou BCEL etc seria menos complicado. Ou você não concorda?

[]s,
Sami

Thiagosc

Mas e se usassem “templates” para as classes, apenas adicionando os atributos e/ou métodos em determinados pontos marcados dentro de uma String que represente o código de uma classe? Essas “marcações” poderiam ser arbitrariamente criadas pelo desenvolvedor e a aplicação ficaria responsável por removê-las/substituí-las antes de compilar.

Eu não conheço essa JSR, nem sei se isso é possível, estou apenas divagando.

Luca

Olá

Respondendo ao Sami e ao Thiago

Realmente a serventia desta JSR ainda colocará em cheque a imaginação dos desenvolvedores. Eu imagino algumas brincadeiras possíveis. Mas teria medo de incluir isto em alguma aplicação séria que precisasse de segurança.

Não vejo muitas semelhanças no ato de fazer entre compilar código de forma programática e modificar classes prontas via alteração de byte codes. Porém os resultados bons ou ruins podem ser parecidos.

Ainda não avaliei direito as implicações de ter um compilador disponível e como um cracker poderia se valer dele para modificar alguma regra. Ainda estou na fase de descobrir que a JSR existe (no tools.jar). As próximas 2 fases serão: saber para que serve e depois descobrir os inconvenientes.

A idéia dos templates é razoável para criar uma família de classes que obedecessem rigidamente alguma regra imposta. Mas como disse antes: a imaginação voa sem limites.

Já percebi que nos últimos builds do Java 6 eles modificaram o nome de classe em relação ao que está na JSR. Então percebe-se que até o lançamento alguma coisa ainda pode mudar. O Build atual de 13/07 é o B91.

[]s
Luca

J

Luca:
Será que a Sun está com enorme capacidade ociosa e fica brincando de colocar mais coisas no Java só para competir com o alemão do Janino?

Este assunto é realmente novo e ainda não saiu em mais do que 2 ou 3 lugares por aí. Você acha que eu perdi tempo a toa estudando a JSR e que não deveria ter trazido para o GUJ porque isto não é nenhuma novidade. Eu achei que seria útil trazer para o GUJ pois para mim a inclusão desta facilidade DENTRO do Java só será possível a partir do Java 6.

Sim e não. Essa JSR vem do esforço da SUN de criar uma base no Java para as IDE. Hoje, a única IDE que faz isso (usa um compilador interno, sem precisar do JDK) é o eclipse. E eles, nunca iriam pegar algo do Eclipse.

Hoje, ferramentas como Maven e IDEA (próxima versão) já estão fazendo uso do compilador do Eclipse.

Em momento algum eu disse que era “perda de tempo” ou qualquer conotação negativa com seu post. Novamente, eu só apontei soluções já existente. Se são boas ou ruins, ai cada um decide. Eu já usei as três, muita gente usa as três (o respeitadissimo drools usa o Janino, e na versão mais nova agora (JBoss Rules) o eclipse com o commons-jci.

O common-jci não é um compilador por si só, é uma interface de acesso mais amigavel ao eclipse, groovy e um outro que não me lembro.
E eu esqueci de apontar o (agora JBoss) Javassist, utilizado no projeto de AOP deles, que dentre outras coisas pega um String e tranforma em uma classe.

Bem, achei que vocês ficaram tão felizes com a possibilidade de compilar uma classe dentro do programas de vocês que achei que seria legal você saberem que isso já é possivel. Mas, na boa? Deixa pra lá. Em momento algum eu quis desmerecer o seu post. Se foi assim que foi recebido, me desculpe. Da próxima vez eu mando uma MP para você não se sentir ofendido.

jack_ganzha

Oi, Luca, não era sobre testar um metodo do ponto de vista de validar o funcionamento, era mais sobre verificar como funciona um metodo ou trecho de codigo. Por exemplo, hoje precisei lembrar como o seguinte trecho funciona:

URL url = new URL("http://www.guj.com.br/arquivoqualquer.txt");
URLConnection conn = url.openConnection();
System.out.println(conn.getHeaderField(null));

Ao inves de escrever uma classe com main - ou um metodo de teste - eu queria apenas abrir um console e mandar brasa. :smiley:

valeuz…

Luca

Olá

Ao contrário do que dizia nesta antiga mensagem do fórum da Sun, o pacote javax.tools funcionará com o JRE.

[]s
Luca

Sami_Koivu

Mas e se usassem “templates” para as classes, apenas adicionando os atributos e/ou métodos em determinados pontos marcados dentro de uma String que represente o código de uma classe? Essas “marcações” poderiam ser arbitrariamente criadas pelo desenvolvedor e a aplicação ficaria responsável por removê-las/substituí-las antes de compilar.

Eu não conheço essa JSR, nem sei se isso é possível, estou apenas divagando.

Confesso que não tinha pensado nisso. Assim, até faz sentido.

Vi na pagina da JSR que um dos usos também é para compilar os Servlets criados dos JSP:

Eu sou o único de pensar que, tomando em consideração a quantidade de desenvolvimento web que está acontecendo, a compilação JSP :arrow: classe Servlet poderia ser bem mais sofisticado? Quer dizer, seria legal se nos StackTrace eu poderia ver o nome do meu arquivo JSP e a linha de código no meu arquivo fonte, e não do Servlet gerado pelo container (que não me ajuda nem um pouco).

Criado 14 de julho de 2006
Ultima resposta 17 de jul. de 2006
Respostas 21
Participantes 9