sexta-feira, 31 de julho de 2009

Java ScriptEngine

0

Estava eu pensando esses dias, se posso executar código java via Jruby por que não o contrário? Quais as minhas chances de usar Jruby dentro do Java?
Então la fui eu ao oraculo, e começei a buscar, ouvi falar de um JSR XXX (preencha com o número que quiser, nunca me lembro desses números, que pra mim são irrelevantes), que define o Java ScriptEngine, que nada mais é do que usar scripts dentro do Java, no Java 6, já vem com superte a Rhino (JavaScript), embutido, mas exemplos usando JavaScript tem de monte, vou lhes mostrar como instanciar uma classe via JRuby e chamar alguns metodos dessa classe no java. Não vou dizer que isso vai ficar bom, mas enfim, quem sabe melhorem futuramente essas engines, Mesmo assim você não precisa massacrar seu codigo java para migra-lo para JRuby, pode simplemente adaptar o codigo do JRuby no Java. Vamos ao exemplo, primeiramente vejamos quais nossas engines disponiveis na nossa versão.


import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngineManager;

public class Main {

public static void main(String[] args) throws Exception{
ScriptEngineManager manager = new ScriptEngineManager();
for(ScriptEngineFactory factory : manager.getEngineFactories()){
System.out.println(factory.getEngineName());
}
}
}


A saida deve ser Mozilla Rhino, lembre-se java 6, eu não tenho bem certeza, mas acho que o ScriptEngine está disponivel na versão 5, porém sem nenhuma engine disponivel.
E ai tio e agora como que nos faz?
Vamos adicionar o Jruby, no site do projeto baixem os script-engines, com isso temos as libs de diversas linguagens suportadas que podemos utilizar, para nos interessa, o que esta dentro da pasta jruby/build, o jruby-engine.jar deve ser adicionado ao seu classpath, ainda existem outro jar a ser adicionado, se você olhar outros tutoriais, ele vai passar diversos jar que não estão mais no $JRUBY_HOME/lib, ignore :), adicione ao classpath do seu projeto somente o jruby.jar, e agora sim. Se executar o programinha de antes deve aparecer agora


Mozilla Rhino
Jruby Engine


Vamos para o nosso querido Hello World (eu sei, eu sei, todos vocês amam o Hello World (: )


import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;

public class Main {

public static void main(String[] args) throws Exception{
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("jruby");//Buscamos a Engine do Jruby
engine.eval("puts 'Hello World'");//Codigo JRuby
}
}


ao executar temos a mesma saida do Println, não é magico? Heeheh, um puts executado via java. Sei exatamente o que a maioria pensou, vou ter que por todo o codigo Jruby num String? A reposta é não :), a não ser que você queira fazer isso, mas eu não aconselho.
Existem outros metodos para recuperar as engines, e um deles é por extensão, poderiamos ter usado o metodo getEngineByExtension e passar como parametro o “rb”, e teriamos o Jruby.
Vamos criar então uma classe bem bunito um arquivo .rb

class Teste
attr_accessor :name, :age

def set_name(name)
self.name = name
end

def set_age(age)
self.age = age
end

def toString
self.name+" "+self.age.to_s
end
end


Lembrando que o toString sobrescreve o metodo toString do java sem problemas algum, os metodos set_ foram definidos para seguir as convensões do ruby, e isso vai tornar nosso codigo java feio, e não digam que não avisei. Vamos criar uma pequena interface


public interface Teste {
String name();
void set_name(String name);
Integer age();
void set_age(Integer age);
}


notem o estilo que foi declarado os metodos set_ na interface tbm, deve haver alguma maneira de fazer isso automatico, se alguem souber me avisa :)

E agora tio? Vamos brincar um pouco de ScriptEngine?


public static void main(String[] args) throws Exception{
ScriptEngineManager manager = new ScriptEngineManager();
for(ScriptEngineFactory factory : manager.getEngineFactories()){
System.out.println(factory.getEngineName());
}
ScriptEngine engine = manager.getEngineByName("jruby");
engine.eval(new FileReader("src/com/rollingwithcode/testejruby/teste.rb"));//arquivo .rb
Object instance = engine.eval("@teste = Teste.new");//crio a instancia
Invocable inv = (Invocable) engine;
Teste teste = inv.getInterface(instance, Teste.class); //converto a classe em uma Interface Java
teste.set_name("Rafael");
teste.set_age(21);
System.out.println(teste.toString());
System.out.println(teste.name());
}


E adivinhem a saida:

Rafael 21
Rafael


Tudo isso só pra misturar um pouco de Ruby com java, credo, parece coisa de loco :)

vou investigar mais algo, e ver se existem maneiras de melhorar isso.

Abraços até a próxima







0 comentários:

 
Design by ThemeShift | Bloggerized by Lasantha - Free Blogger Templates | Best Web Hosting