How can I run a Groovy class from the command-line within a Grails environment?
Asked Answered
M

2

4

I'm using Grails 2.1.0, and I have a Groovy class that I've written that's not dependent on services, controllers, or any of the other Grails goodness. It uses some .jar libraries and other classes that are already in the Grails classpath.

I want to:

  • Run the Groovy class (or a Java class, it shouldn't mattter) use the other libraries/classes that Grails already has on its classpath (not services, not controllers, none of that).
  • Be able to access the command line arguments [this is required]
  • Does not require bootstrapping the entire Grails environment (I need the classpath obviously, but nothing else)

Ideally, I'd like to be able to do something like this:

java -classpath (I_HAVE_NO_IDEA_HOW_TO_DETERMINE_THIS) com.something.MyClass param1 param2 param3

Things I've already looked into:

  • Using "grails create-script" which results in a Gant script.
  • Using "grails run-script"

The first one (using a Gant script) seems horribly wrong to me. Using an Gant script as some sort of intermediary wrapper seems to require bootstrapping the whole Grails environment, plus I have to figure out how to get a reference to the actual class I want to call which seems to be difficult (but I Am Not A Gant Expert, so enlighten me). =)

The second one (using run-script) sort of works... I've used this approach to call service methods before, but it has two problems: first, it bootstraps the entire Grails environment; second, there does not appear to be any way to pass the command-line arguments easily.

Really, I just want the stuff in the classpath (and my command-line parameters) and to be able to call the main() method of my class with minimial frustration. That being said, if you can come up with a working example of any sort that solves the issue (even if it involves some intermediary Gant or other class) I'll be happy to use that approach.

Thanks.


Update: A solution that works with a Gant task, still open to better ideas if anyone has any...

In scripts/FooBar.groovy

includeTargets << grailsScript("_GrailsInit")

target(main: "Runs a generic script and passes parameters") {
   def myclass = classLoader.loadClass('com.whatever.scripting.GenericRunScript') 
   myclass.execute(args);
}
setDefaultTarget(main)

In src/groovy/com/whatever/scripting/GenericRunScript.groovy

package com.whatever.scripting
class GenericRunScript {
    public static execute(def args) {
        println "args=" + args.inspect()
    }
}

Then from the command line, at while in the root directory of the Grails project:

$ grails compile 
| Environment set to development.....
| Compiling 2 source files.

$ grails foo-bar test one two
| Environment set to development....
args='test\none\ntwo'

Note 1: When I first did this, I kept forgetting the compile statement, so I added that in.

Note 2: Yes, the args are separated by carriage returns; fixing that is left as an exercise to the reader.

Metcalf answered 22/5, 2013 at 21:53 Comment(5)
Hey, would you mind posting your solution to this as an answer? It would make this easier to read and find. Thanks!Causeuse
Indeed, you have to compile with this approach. Grails doesn't do it automatically because the class is loaded with classLoader. However, you can add "compile" as a dependency to your target in FooBar.groovy. Just one line: depends(compile), following the examples in 4.1. in grails.org/doc/1.1.1/guide/4.%20The%20Command%20Line.html. It really does compile.Radix
Also, another way to pass parameters is to use -Dproperty=value, then retrieve them with System.getProperty.Radix
See #23746417 for my answer when using Grails 2.4.3Skulduggery
Running in Grails 2.4.3 and having errors with Tomcat? See #23746417Skulduggery
R
0

As described in http://grails.org/doc/latest/guide/commandLine.html, you can include targets _GrailsClasspath and _GrailsArgParsing, and whatever else you need. For example, if you want to parse command-line arguments without creating a second script:

$ grails create-script ArgsScript
| Created file scripts/ArgsScript.groovy

Now edit the script scripts/ArgsScript.groovy as follows:

includeTargets << grailsScript("_GrailsArgParsing") // grailsScript("_GrailsInit")

target(main: "The description of the script goes here!") {
    println argsMap
    for (p in argsMap['params']) 
      println p
}
setDefaultTarget(main)

See the result:

$ grails args-script one two three=four
| Environment set to development....
[params:[one, two, three=four]]
one
two
three=four

Update: well, it is not as easy as I thought. Basically, you can either run a script as a Gant task, e.g. by doing grails myscript, or as a script, e.g. by doing grails run-script src/groovy/MyScript.groovy. In the first case you have access to parameters, as I already explained, but you still miss some of the Grails environment, which is, perhaps, a bug. For example, you can't really access scripts or classes defined in src/groovy/ from a Gant task. On the other hand, as was already discussed, if you use run-script, you can't get the arguments.

However, you can use System.getProperty to pass command-line arguments with the -Dproperty=value syntax. Also see Java system properties and environment variables

Radix answered 2/10, 2013 at 21:11 Comment(0)
S
0

The way described above would work but all grails facility will be gone including domains and dependencies.

If you require everything that you have defined in your grails project, the run-script command will do the trick

grails run-script [path to your groovy file]

http://grails.org/doc/latest/ref/Command%20Line/run-script.html

Scallion answered 3/10, 2013 at 23:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.