Calling a Groovy function from Java - java

How do you call a function defined in a Groovy script file from Java?
Example groovy script:
def hello_world() {
println "Hello, world!"
}
I've looked at the GroovyShell, GroovyClassLoader, and GroovyScriptEngine.

Assuming you have a file called test.groovy, which contains (as in your example):
def hello_world() {
println "Hello, world!"
}
Then you can create a file Runner.java like this:
import groovy.lang.GroovyShell ;
import groovy.lang.GroovyClassLoader ;
import groovy.util.GroovyScriptEngine ;
import java.io.File ;
class Runner {
static void runWithGroovyShell() throws Exception {
new GroovyShell().parse( new File( "test.groovy" ) ).invokeMethod( "hello_world", null ) ;
}
static void runWithGroovyClassLoader() throws Exception {
// Declaring a class to conform to a java interface class would get rid of
// a lot of the reflection here
Class scriptClass = new GroovyClassLoader().parseClass( new File( "test.groovy" ) ) ;
Object scriptInstance = scriptClass.newInstance() ;
scriptClass.getDeclaredMethod( "hello_world", new Class[] {} ).invoke( scriptInstance, new Object[] {} ) ;
}
static void runWithGroovyScriptEngine() throws Exception {
// Declaring a class to conform to a java interface class would get rid of
// a lot of the reflection here
Class scriptClass = new GroovyScriptEngine( "." ).loadScriptByName( "test.groovy" ) ;
Object scriptInstance = scriptClass.newInstance() ;
scriptClass.getDeclaredMethod( "hello_world", new Class[] {} ).invoke( scriptInstance, new Object[] {} ) ;
}
public static void main( String[] args ) throws Exception {
runWithGroovyShell() ;
runWithGroovyClassLoader() ;
runWithGroovyScriptEngine() ;
}
}
compile it with:
$ javac -cp groovy-all-1.7.5.jar Runner.java
Note: Runner.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
(Note: The warnings are left as an exercise to the reader) ;-)
Then, you can run this Runner.class with:
$ java -cp .:groovy-all-1.7.5.jar Runner
Hello, world!
Hello, world!
Hello, world!

The simplest way is to compile the script into a java class file and just call it directly. Example:
// Script.groovy
def hello_world() {
println "Hello, World!"
}
// Main.java
public class Main {
public static void main(String[] args) {
Script script = new Script();
script.hello_world();
}
}
$ groovyc Script.groovy
$ javac -classpath .:$GROOVY_HOME/embeddable/groovy-all-1.7.5.jar Main.java
$ java -classpath .:$GROOVY_HOME/embeddable/groovy-all-1.7.5.jar Main
Hello, World!

Either
Compile as ataylor suggests
Use JSR-223 as explained here
If you are using Spring, have a groovy class that implements a Java interface, and inject into your code with:
<lang:groovy id="messenger" script-source="classpath:Messenger.groovy">
<lang:property name="message" value="I Can Do The Frug" />
</lang:groovy>
One advantage of the spring approach is the concept of 'refreshable beans'. That is, Spring can be configured to monitor your script file for modifications, and replace at runtime.

You too can use the Bean Scripting Framework to embed any scripting language into your Java code. BSF give you the opportunity of integrate other languages, but is not native integration.
If you are clearly focused to use Groovy the GroovyScriptEngine is the most complete solution.
=)

One simple example:
import groovy.lang.GroovyClassLoader;
import groovy.lang.Script;
public class GroovyEmbedder {
static public final String GROOVY_SCRIPT=
"println ('Hello World !')";
static public void main(String[] args) throws Exception {
((Script) new GroovyClassLoader().parseClass(GROOVY_SCRIPT).newInstance()).run();
}
}
Testing
> javac -cp groovy-all-2.4.10.jar GroovyEmbedder.java
> java -cp groovy-all-2.4.10.jar:. GroovyEmbedder
Hello World !

Just more elegant ways:
GroovyScriptEngine engine = new GroovyScriptEngine( "." )
Object instance = engine
.loadScriptByName(scriptName)
.newInstance()
Object result = InvokerHelper.invokeMethod(instance, methodName, args)
And if script class extends groovy.lang.Script:
Object result = engine
.createScript(scriptName, new Binding())
.invokeMethod(methodName, args)
No need to extend groovy.lang.Script if you just want call main method of your groovy class:
Object result = engine
.createScript(scriptName, new Binding())
.run()

Related

Running groovy script in Java code

Hello I am looking to run a groovy script inside Java code but I didn't find many tutorial about that.
I have a String that contain a groovy script :
private String processingCode = "def hello_world() { println \"Hello, world!\" }";
I have also downloaded the Groovy SDK.
Which groovy jar should I include in java project ? And how to execute the script in Java ?
What you need is a groovy-all dependency and GroovyShell.
Main class will be:
package lol;
import groovy.lang.GroovyShell;
public class Lol {
public static void main(String[] args) {
String processingCode = "def hello_world() { println 'Hello, world!' }; hello_world();";
GroovyShell shell = new GroovyShell();
shell.evaluate(processingCode);
}
}
Here is a demo.
Use gradle run to run it.

Loading java library functions to Luaj

I am stuck with loading java functions so that it can be called from lua file using luaj.
What i currently do is create something like this :
in some_package/aif.java :
package some_package;
public class aif extends TwoArgFunction {
public aif() {
}
#Override
public LuaValue call(LuaValue modname, LuaValue env) {
LuaValue library = tableOf();
library.set("foo", new foo());
env.set("aif", library);
return library;
}
//the rest contains the implementations of java functions
}
and then in lua file :
require "some_package/aif"
--etc ...
and then in Main.java file :
public static void Main(String[] args) {
String script = "lib/some_lua_file.lua";
globals = JsePlatform.standardGlobals();
LuaValue chunk = globals.loadFile(script);
chunk.call( LuaValue.valueOf(script) );
}
this code works , but what i want is that in lua file we dont have to use "require". I have achieved this similarly but in c++ using this line :
luaL_requiref(L, "aif", luaopen_aiflib, 1);
can we do like that in luaj? i tried :
globals.load(new aif());
but gets Exception in thread "main" org.luaj.vm2.LuaError: index expected, got nil (variable env in call function of aif class is nil)
anybody knows how to setup aif as lua libary to use with luaj?
You can write your MyXArgImpl like the following:
package mypackage;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.lib.ZeroArgFunction;
public class MyZeroArgImpl extends ZeroArgFunction {
public LuaValue call() {
return valueOf("My Zero Arg Implementation");
}
}
and then add it to your LUA as the following:
LuaValue globals = JsePlatform.standardGlobals();
globals.get("dofile").call( LuaValue.valueOf(yourScriptfile));
globals.set("callMyFunction", new MyZeroArgImpl());
Now you can call your function inside your LUA script even without require('...'):
print(callMyFunction())
I have found the answer after looking at the luaj implementation of Lua library.
i modified my code :
package some_package;
public class aif extends OneArgFunction{
public aif() {
}
#Override
public LuaValue call(LuaValue env) {
Globals globals = env.checkglobals();
LuaTable aif = new LuaTable();
aif.set("foo", new foo());
env.set("aif", aif);
globals.package_.loaded.set("aif", aif);
return aif;
}
//the rest contains the implementations of java functions
}
I code the aif class to TwoArgFunction is because the tutorial said to do so. Now with the above code, no need to require the class in lua file
Lets say your script that you are loading has a function "receive_aif"
function receive_aif( aifObj )
--This is how you can invoke public function associated with aifObj
aifObj:someAifFunction()
end
From java, you can pass aif instance as: (This should work with any java object )
aif aifObj = new aif()
LuaValue receive_aif_handle = globals.get("receive_aif");
LuaValue retvals = receive_aif_handle.call( CoerceJavaToLua.coerce( aifObj ) );
I am using similar constructs in my application using "3.0 aplha-2" release

"Hello World" with Java annotations

Problem description: Compile 2 jar files independently, without having to include each other on classpath; and at runtime, include both and invoke main() in one jar to print a string on stdout. Parts of the output string have to come from the 2nd jar.
Constraints: The solution cannot be IDE-dependent or use any other jar files.
Answering what have I done so far: My Solution is described below.
Reason to ask the question: I am trying to figure out if/how to use annotations to solve this problem (hopefully in a more elegant manner), but cannot find any suitable documentation or tutorial. I appreciate any pointer(s) for that also.
My Solution: A batch file (on Unix, please change the backslash to forward slash, semicolon to colon and the rem's to #) as follows:
rem Compile and package the testing class (Main) without any library
javac -d target core\*.java
cd target
jar cvf ..\main.jar .\core
cd ..
rem Compile and package the Greeting and Greeted classes as a library
javac -d lib impl\*.java
cd lib
jar cvf ..\mylib.jar .\impl
cd ..
rem Use the two parts above at runtime and execute main() in Main class
java -cp main.jar;mylib.jar core.Main
There are 2 files in the impl directory and 2 in the core, as follows:
/* File: impl/Greeting.java */
package impl;
public class Greeting {
public String getGreeting () {
return "Hello";
}}
/* File: impl/Greeted.java */
package impl;
public class Greeted {
public String getGreeted () {
return "world";
}
/* File: core/Main.java */
package core;
public class Main {
private String greeting = "Learn annotations", greeted = "keep using Java",
// Can read the following 4 values from a configuration file, too
// Trying to see if we can get these using Java annotations
greetingClassName = "impl.Greeting", greetingMethod = "getGreeting",
greetedClassName = "impl.Greeted", greetedMethod = "getGreeted";
public Main () {
try {
MyRunTime runTime = new MyRunTime();
Object gting = runTime.getInstance(greetingClassName),
gted = runTime.getInstance(greetedClassName),
g1Str = runTime.getResponseNoArg (gting, greetingMethod),
g2Str = runTime.getResponseNoArg (gted, greetedMethod);
if (g1Str instanceof String) greeting = (String) g1Str;
if (g2Str instanceof String) greeted = (String) g2Str;
} catch (Exception ex) {
System.err.println ("Error in Library loading: " + ex.getMessage());
}}
public void greet () {
System.out.println (greeting + ", " + greeted + "!");
}
public static void main (String[] args) {
new Main().greet();
}}
/* File: core/MyRunTime.java */
package core;
import java.lang.reflect.*;
public class MyRunTime {
public Object getResponseNoArg (Object anInstance, String methodName) throws
NoSuchMethodException,
IllegalAccessException,
InvocationTargetException {
Method method = anInstance.getClass().getMethod (methodName);
return method.invoke (anInstance);
}
public Object getInstance (String className) throws
ClassNotFoundException,
InstantiationException,
IllegalAccessException {
Class c = Class.forName (className);
return c.newInstance();
}
}
That's it. I would also like not to mess with the ClassLoader unless absolutely necessary. Once I get a handle on how to do this with annotations, I can look into passing arguments and go forward. Thank you for your help.
I wouldn't use Annotations for this - it's probably worth covering what Annotations are and where they are best used.
Instead I would do something like:
Place different files in each jar
A main class to each jar file, which does the same thing: list the files on the classpath
I think that would meet the project requirements.
To list the files on the classpath you could so something like:
public class Main {
public static void main(final String[] args) throws java.lang.Throwable {
final String list = System.getProperty( "java.class.path" );
for (String path : list.split( ";" )) {
java.io.File object = new java.io.File( path );
if ( object.isDirectory() )
for ( String entry : object.list() ) {
java.io.File thing = new java.io.File( entry );
if ( thing.isFile() )
System.out.println( thing );
else if( object.isFile() )
System.out.println( object );
}
}
}
}

ProcessBuilder - Start another process / JVM - HowTo?

I'm writing a network app, where each Client has a Singleton ClientManager.
For testing, I would like to create several clients (each in their own VM / process) without starting the program by hand n-times.
The following two questions on stackoverflow already describe how-to do that:
Is this really the best way to start a second JVM from Java code?
Java: Executing a Java application in a separate process
My Code is based on these, but it's not working:
The main program doesn't continue after spawn is called.
The spawned code doesn't get executed.
Here's the complete code using ProcessBuilder:
public class NewVM {
static class HelloWorld2 {
public static void main(String[] args) {
System.out.println("Hello World");
System.err.println("Hello World 2");
}
}
public static void main(String[] args) throws Exception {
startSecondJVM(HelloWorld2.class, true);
startSecondJVM(HelloWorld2.class, false);
System.out.println("Main");
}
public static void startSecondJVM(Class<? extends Object> clazz, boolean redirectStream) throws Exception {
System.out.println(clazz.getCanonicalName());
String separator = System.getProperty("file.separator");
String classpath = System.getProperty("java.class.path");
String path = System.getProperty("java.home")
+ separator + "bin" + separator + "java";
ProcessBuilder processBuilder =
new ProcessBuilder(path, "-cp",
classpath,
clazz.getCanonicalName());
processBuilder.redirectErrorStream(redirectStream);
Process process = processBuilder.start();
process.waitFor();
System.out.println("Fin");
}
}
What am I doing wrong???
Btw:
I'm using Eclipse.
The Singleton problem is a simplified example. Please do not suggest creating a factory.
Solution: HelloWorld2 mustn't be an inner class.
I suggest you make HelloWorld2 a top level class. It appears java expects a top level class.
This is the code I tried.
class Main
{
static class Main2
{
public static void main ( String [ ] args )
{
System . out . println ( "YES!!!!!!!!!!!" ) ;
}
}
public static void main ( String [ ] args )
{
System . out . println ( Main2 . class . getCanonicalName ( ) ) ;
System . out . println ( Main2 . class . getName ( ) ) ;
}
}
class Main3
{
public static void main ( String [ ] args )
{
System . out . println ( "YES!!!!!!!!!!!" ) ;
}
}
getCanonicalName and getName return different names. Which one is right? They are both wrong.
Main3 works.
I think I see a fix for part of the problem: process.waitFor() prevents control from returning to main() before the subprocess ends.
To figure out why your spawned process isn't starting, I'd recommend printing out all the arguments to the ProcessBuilder constructor and checking that a hand-called JVM called with those arguments succeeds. In particular, you need that class name to be the name of a class having a static void main(String[]).

Executing script inside method with BeanShell

I'm not really sure how I can explain this, but here goes:
I want to be able to "insert" some commands into parts of my code which will be loaded from external files. To parse and execute these commands, I presumably have to use some scripting like BeanShell's eval method. The problem is that it doesn't seem to recognize the instance/method it's inside of. As a very basic example, I want to do something like
public void somethingHappens()
{
Foo foo = new Foo();
Interpreter i = new Interpreter();
i.eval("print(foo.getName());");
}
Is this possible? Should I use other scripting tools?
If you're using 1.6, you can use the built in JavaScript support.
The Java Scripting Programmer's Guide explains how to import Java classes into your script.
Code example 9 in this article explains how to pass objects into the script's scope.
Using beanshell, this is something you can try
package beanshell;
import bsh.EvalError;
import bsh.Interpreter;
public class DemoExample {
public static void main( String [] args ) throws EvalError {
Interpreter i = new bsh.Interpreter();
String usrIp = "if(\"abc\".equals(\"abc\")){"
+ "demoExmp.printValue(\"Rohit\");"
+ "}";
i.eval(""
+ "import beanshell.DemoExample;"
+ "DemoExample demoExmp = new beanshell.DemoExample();"
+ ""+usrIp);
}
public static void printValue(String strVal){
System.out.println("Printing Value "+strVal);
}
}

Categories