How can I call a Java code snippet from JRuby code? My code snippet is really short, actually it's just a set of a few Java statements.
Explained here on how to call existing Java code from JRuby. The most basic usage:
require 'java'
java.lang.System.out.println("Hello, world!")
As a bit more complex example, if you want to import your arbitrary package (say, 'foo.bar.baz') from a JAR, you can do this:
require 'java'
require 'foobarbaz.jar'
def foo
Java::Foo
end
shiny_thingy = foo.bar.baz.Thingy.new("Shiny")
shiny_thingy.shine()
If you want to evaluate a string as if it was Java, you would need to compile it first; you can use the techniques in this question, but Java generally frowns on autogenerated code, and it is not trivial to do it. Or you can translate it into JRuby, calling Java classes as described above, and skip the compilation issue.
We might be able to help better if we knew what your snippet consisted of.
EDIT: Here is the adaptation of the linked code that will instantiate an arbitrary class. Be aware that it will create .class
files, which is AFAIK inevitable when a compilation step is involved. The code assumes a subdirectory named tmp
exists; adapt to your use case.
shiny_source = <<-EOF
package foo.bar.baz;
public class Shiny {
public Shiny() {
System.out.println("I'm shiny!");
}
}
EOF
require 'java'
java_import javax.tools.SimpleJavaFileObject
java_import java.net.URI
class JavaSourceFromString < SimpleJavaFileObject
def initialize(name, code)
uri = "string:///" + name.gsub('.', '/') + Kind::SOURCE.extension
super URI.create(uri), Kind::SOURCE
@code = code
end
def getCharContent(ignore_encoding_errors)
@code
end
end
java_import javax.tools.ToolProvider
java_import java.io.StringWriter
java_import java.net.URL
java_import java.net.URLClassLoader
compilation_path = java.nio.file.Paths.get('tmp').to_absolute_path.to_s
jc = ToolProvider.get_system_java_compiler
raise "Compiler unavailable" unless jc
jsfs = JavaSourceFromString.new('foo.bar.baz.Shiny', shiny_source)
file_objects = [jsfs]
ccl = java.lang.Thread.current_thread.get_context_class_loader
classpath = ccl.getURLs.to_a.join(java.io.File::pathSeparator)
options = ['-d', compilation_path, '-classpath', classpath]
output = StringWriter.new
success = jc.get_task(output, nil, nil, options, nil, file_objects).call
raise output unless success
url = URL.new("file:" + compilation_path + "/")
ucl = URLClassLoader.new_instance([url].to_java(URL))
shiny_class = ucl.load_class('foo.bar.baz.Shiny')
shiny_class.new_instance