Nos últimos tempos tenho dedicado boa parte do meu tempo livre estudando JRuby. Tem sido uma verdadeira diversão!
Com o objetivo de compartilhar um pouco do que tenho aprendido, eis aqui este post…
Quer dizer que o osrevni inverso também é verdade?
Muito se fala da capacidade do JRuby de acessar código Java de maneira tão natural quanto o faz com seu próprio código - o que é definitivamente fantástico. Mas não tenho visto muitos exemplos de código Java acessando código JRuby. Por quê? Não sei dizer. Talvez porque não tenham visto tanta utilidade nisso. Essa não é minha opinião, já que tenho interesse em implementar algumas coisas em JRuby e usar a partir do Java.
Uma das coisas que fiz nesses meus estudos sobre usar JRuby a partir de Java foi testar o compilador jrubyc para gerar .class, mas não cheguei bem onde eu queria - até troque umas palavras com Charles Nutter a respeito -, porque o .class gerado por ele não é do tipo que se pode instanciar e usar diretamente num código Java, dada a natureza totalmente dinâmica de Ruby. Nas palavras do próprio Charles:
The code compiled by jrubyc is not a “normal” Java class[...] This is not a Java class you can instantiate and call methods on directly from Java[...].
Como não desisti, tenho algumas alternativas para compartilhar.
OBS.: Para executar os exemplos apresentados é necessário ter jruby.jar no classpath do seu projeto. Quando escrevi este post estava usando a versão 1.0, porque não havia uma versão mais atual na máquina que eu estava usando. Mas agora já atualizei o código para a versão 1.1.3.
Primeira alternativa: JRuby puramente Ruby
No exemplo abaixo, criou uma classe Ruby comum - sem qualquer recurso específico do JRuby - e, logo após, a carrego, instancio e executo seu método a partir do Java.
matematica_apenas_ruby.rb
class MatematicaApenasRuby
def soma(a, b)
a + b
end
end
MatematicaApenasRubyTest.java
public class MatematicaApenasRubyTest {
public static void main(String args[]) throws Exception {
List pathsLoad = new ArrayList();
pathsLoad.add("/Workspace/Ruby/IntegracaoJava/lib/");
Ruby rubyRuntime = JavaEmbedUtils.initialize(pathsLoad);
rubyRuntime.getLoadService().load("matematica_apenas_ruby.rb", false);
Object mat_ruby = rubyRuntime.evalScriptlet("MatematicaApenasRuby.new");
Integer res_ruby = (Integer)JavaEmbedUtils.invokeMethod(rubyRuntime, mat_ruby, "soma", new Integer[] {3, 2}, Integer.class);
System.out.println("Soma 3 + 2 invocando diretamente JRuby: " + res_ruby);
}
}
O que esse código Java faz é bem simples, ele:
1- Inicializa um ambiente de runtime para Ruby, indicando onde estão os arquivos .rb;
2- Executa o script de criação da classe MatematicaApenasRuby;
3- Executa o script de instanciação da classe MatematicaApenasRuby;
4- E, por fim, invoca o método soma passando dois parametros.
Que tal, acho simples? Pois muito bem, continuemos…
Segunda alternativa: JRuby implementando Java
Neste segundo exemplo, o que eu faço é criar uma classe JRuby que estende uma classes Java abstrata, o que facilita ainda mais na hora de usar a partir do Java. Vejamos como fica.
matematica_impl_java.rb
require 'java'
class MatematicaImplJava < Java::IntegracaoPoliglota::Matematica
def soma(a, b)
a + b
end
end
Matematica.java
package integracao.poliglota;
public abstract class Matematica {
public abstract int soma(int a, int b);
}
MatematicaImplJavaTest.java
public class MatematicaImplJavaTest {
public static void main(String args[]) throws Exception {
List pathsLoad = new ArrayList();
pathsLoad.add("/Workspace/Ruby/IntegracaoJava/lib/");
Ruby rubyRuntime = JavaEmbedUtils.initialize(pathsLoad);
rubyRuntime.getLoadService().load("matematica_impl_java.rb", false);
Object mat_impl_java = rubyRuntime.evalScriptlet("MatematicaImplJava.new");
Matematica matematica = (Matematica)JavaEmbedUtils.rubyToJava(rubyRuntime, (IRubyObject)mat_impl_java, Matematica.class);
System.out.println("Soma 10 + 2 usando a interface Java: " + matematica.soma(10, 2));
}
}
E esta alternativa, gostou? Eu gostei bastante. Porque no meu caso, o que eu quero é poder definir uma interface em Java e implementar com JRuby a la Ruby Way e depois usar no Java. É claro que não estou levando em conta o fator “performance”, só estou considerando o fator “alternativa de implemententação”. Só isso.
Mas vamos lá, o que esse código faz?
1- A classe JRuby estende uma classe Java abstrata, como dito antes;
2- A classe que faz o teste, em linhas gerais, faz um cast do objeto JRuby para a classe Java abstrata;
3- E no final das contas, invoca o método da classe Java.
Será que programação poliglota é o futuro?
Se é ou não é, eu não sei. Mas sei que deixei de ser um arquiteto de uma nota só há muito tempo; e estou muito emplogado com JRuby - ele é o melhor dos dois mundos!
E você, o que acha? Deixe um comentário…





