2

I have many groovy scripts which are compiled with GMaven (located in src/main/groovy/somepackage), each script has run(String, String) function and does not have a class:

// script1.groovy
def run(String name, String arg) {
  // body
}


// script2.groovy
def run(String name, String arg) {
  // body
}

I can find them with Reflections library and resolve their types:

final Set<String> scripts = new Reflections(
  "somepackage",
   new SubTypesScanner(false)
).getAllTypes();
for (String script : scripts) {
  run(Class.forName(name));
}

then I have some issues with execution: I can't create scipt instance because it doesn't have public constructor (has only private one with groovy.lang.Reference parameters) and I can't find run method in this type.

The question: how to execute compiled groovy script (with single method and without a class) from Java using reflection properly?

1 Answer 1

2

You can load compiled Groovy scripts from given package using:

Reflections.getSubTypesOf(groovy.lang.Script.class)

It returns a Set<Class<? extends Script>> so you can iterate over those classes, instantiate them and invoke method using Class.invokeMethod(String name, Object args)

ATTENTION: you wont be able to call this method like script.run(string1, string2), because this method does not exist in parent groovy.lang.Script class.

Below you can find an example:

import groovy.lang.Script;
import org.reflections.Reflections;
import org.reflections.scanners.SubTypesScanner;

import java.util.Set;

public class LoadGroovyScriptExample {

    public static void main(String[] args) throws IllegalAccessException, InstantiationException {
        Set<Class<? extends Script>> scripts = new Reflections("somepackage", new SubTypesScanner(false))
                .getSubTypesOf(Script.class);

        for (Class<? extends Script> script : scripts) {
            script.newInstance().invokeMethod("run", new Object[] { "test", "123" });
        }
    }
}

somepackage/script1.groovy

package somepackage

def run(String name, String arg) {
    println "running script1.groovy: ${name}, ${arg}"
}

somepackage/script2.groovy

package somepackage

def run(String name, String arg) {
    println "running script2.groovy: ${name}, ${arg}"
}

Console output

[main] INFO org.reflections.Reflections - Reflections took 93 ms to scan 1 urls, producing 1 keys and 2 values 
running script2.groovy: test, 123
running script1.groovy: test, 123
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.