Using classpath when debugging groovy scripts - groovy

I'm new to Java and Groovy, and this is a really simple question on how to use classpath when debugging groovy scripts.
I setup my Groovy project according to https://gist.github.com/tknerr/42258e761f2a0f95a92b:
$ find src
src
src/main
src/main/groovy
src/main/groovy/impl
src/main/groovy/impl/FooImpl.groovy
src/test
src/test/groovy
src/test/groovy/main.groovy
$ head src/main/groovy/impl/FooImpl.groovy src/test/groovy/main.groovy
==> src/main/groovy/impl/FooImpl.groovy <==
package impl
class FooImpl {
def foo() {
"hello?!"
}
}
==> src/test/groovy/main.groovy <==
println new impl.FooImpl().foo()
And I have already build everything:
$ find build/classes
build/classes
build/classes/groovy
build/classes/groovy/main
build/classes/groovy/main/impl
build/classes/groovy/main/impl/FooImpl.class
build/classes/groovy/test
build/classes/groovy/test/main.class
My goal is to use existing classes in classpath without packaging them into .jar file each time when debugging my groovy scripts, but am wondering why I'm getting the following errors:
cd src/test/groovy
$ ls ../../../build/classes/
groovy
$ groovy --classpath ../../../build/classes/ main.groovy
.../src/test/groovy/main.groovy: 1: unable to resolve class impl.FooImpl
# line 1, column 9.
println new impl.FooImpl().foo()
^
1 error
Same with groovysh.
How can I make it working?

Related

How add dependencies into groovy script?

I try to add HttpBuilder into groovy script, but can do it only manually (Alt+Ctrl+Shift+S add dependencie). But when I start script I have error in line of creating new httpbuilder instance java.lang.ClassNotFoundException: org.apache.http.client.HttpClient. I manualy add HttpClient, butClassNotFoundException: net.sf.json.JSONObject and so on. But when I add Ini library it works fine.
I also tried to use #Grab
main()
def main() {
#Grab(group='org.codehaus.groovy.modules.http-builder', module='http-builder', version='0.7' )
def http = new groovyx.net.http.HTTPBuilder('http://www.codehaus.org')
And have compilation error
Error:Groovyc: While compiling GroovyTests: java.lang.RuntimeException: Error grabbing Grapes -- [download failed: net.sf.json-lib#json-lib;2.3!json-lib.jar]
And net in def http = new groovyx.net.http.HTTPBuilder('http://www.codehaus.org') is red and Cannot resolve a symbol 'net' error
will be glad to any help
Since you have now installed the groovy executables as per the comments, the following code:
#Grab('org.codehaus.groovy.modules.http-builder:http-builder:0.7')
import groovyx.net.http.HTTPBuilder
def http = new HTTPBuilder('https://jsonplaceholder.typicode.com')
def res = http.get(path: '/users')
println "Number of users: ${res.size()}"
should now run and print:
─➤ groovy solution.groovy
Number of users: 10
─➤
(tested on Groovy Version: 2.5.8 JVM: 1.8.0_232 Vendor: AdoptOpenJDK OS: Linux)
One thing that might be disrupting the artifact resolution is if you have a custom grapeConfig.xml file. This file (if it exists) should be under <user home dir>/.groovy/grapeConfig.xml and the default text that groovy uses if no grapeConfig.xml file is present can be found here:
https://github.com/apache/groovy/blob/master/src/resources/groovy/grape/defaultGrapeConfig.xml
In addition, if you need to debug grapes downloads, you should try the following flags (again as mentioned in the comments):
─➤ groovy -Dgroovy.grape.report.downloads=true -Divy.message.logger.level=4 yourGroovyScript.groovy
which should print information on what grapes are actually doing when the resolution fails.
What does your groovy -v look like? i.e. what version of groovy and what jdk are you on?

Compile groovy script statically with command line arguments

I am trying to statically compile a groovy script to speed up it's execution, but am not able to get it to work if command line arguments are used. My actual script is much longer, but the one-line script I use for this question perfectly reproduces my error.
Using the following script (test.groovy)
println(args.length)
This can be compiled with the command groovyc test.groovy and ran by the java command java -cp .;%GROOVY_HOME%\lib\* test and will simply print the number of command line arguments used.
Now, if I provide the script (config.groovy)
withConfig(configuration) {
ast(groovy.transform.CompileStatic)
}
and compile with groovyc -configscript config.groovy test.groovy, I get an error
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
testing.groovy: 1: [Static type checking] - The variable [args] is undeclared.
# line 1, column 9.
println(args.length)
^
1 error
This error only occurs when I attempt to compile statically. I can get it to work by wrapping the script in a class and putting my code in a main method (which, of course, is what the compiler does with a script), but not when I try to just use the script (which is what I prefer to do). For some reason, the variable args is unknown when compiled statically. I've tried this.args but still receive the error. If I try to declare a type for args (String[] args), it no longer receives the command line arguments.
Is there a way to still get the command line arguments when a script is compiled statically this way?
I am using Groovy version 2.4.10 on Windows 7 with Java 8.
The Script works via dynamic evaluation of the bindings object. If you want to use static compilation, you need to use the explicit form, changing your test.groovy script into the following:
String[] args = (String[])binding.getVariable('args')
println args.length
Using your already provided configuration script you do get a static compiled Script. I tested running it this way:
groovyc --configscript config.groovy test.groovy
java -cp .;%GROOVY_HOME%\lib\groovy-2.5.3.jar test 1 2 3
This prints 3.
If you want to not modify test.groovy at all, you can create a new base class:
import groovy.transform.CompileStatic
#CompileStatic
abstract class StaticBase extends Script {
StaticBase() {
}
StaticBase(Binding binding) {
super(binding)
}
String[] getArgs() {
(String[]) getBinding().getVariable("args")
}
}
Since the base class has a method getArgs, then when the test.groovy refers to args, the static compiler picks up the call to that method.
groovyc --configscript config.groovy -b StaticBase test.groovy
java -cp .;%GROOVY_HOME%\lib\groovy-2.5.3.jar test 1 2
The code in test.class has a run method whose code represents this.println(this.getArgs().length)
There's difference in executing Groovy class and running simple script. It's not correct that compiler simply wraps your script in main method, the body of the script will be copied into a run method.
Example:
println(args.length)
will be converted to
import org.codehaus.groovy.runtime.InvokerHelper
class Main extends Script {
def run() {
println(args.length)
}
static void main(String[] args) {
InvokerHelper.runScript(Main, args)
}
}
This compiles fine due to dynamic types.
Now, if we add #CompileStatic annotation to that class, we'll get the error of undeclared variable.
So, you have to wrap your code in class in order to use static compiling.
You can read more about Scripts versus classes in documentation.

What does `configurations.<config>` allow to iterate over?

In the gradle documentation in the section about groovy basic, we have an example:
configurations.runtime.each { File f -> println f }
What the code was supposed to print? I write the simple build script containig this line:
apply plugin: 'java'
configurations.runtime.each { File f -> println f }
dependencies{
project(':api') //This's just a project declared in the settings.gradle
}
and what the gradle check does is print nothing. What does it mean actually?
In general this will iterate over all files resolved for the specified configuration. In your case this configuration is runtime. As you havn't declared any runtime dependencies, no file is printed. Vahid is right that you should put this kind of statements into a task, otherwise it will be called at gradles configuration time on every build invocation, even when just asking for available tasks via "gradle tasks".
you should overwrite gradle check method:
check << {
configurations.runtime.each { File f -> println f }
}
then run
gradle check

What should CLASSPATH be set to in order to use NekoHTML in Groovy?

I have found several snippets that use NekoHTML library in Groovy scripts, e.g.
def page = new XmlSlurper(new org.cyberneko.html.parsers.SAXParser()).parse('http://groovy.codehaus.org/')
def data = page.depthFirst().grep{ it.name() == 'A' && it.#href.toString().endsWith('.html') }.'#href'
data.each { println it }
So I downloaded Groovy, and then I downloaded NekoHTML.
NekoHTML is located here:
D:\TOOLS\nekohtml-1.9.18\
When I run the snippet, I get:
D:\SCRIPTS\webtesting.groovy: 4: unable to resolve class org.cyberneko.html.parsers.SAXParser
# line 4, column 27.
def page = new XmlSlurper(new org.cyberneko.html.parsers.SAXParser()).parse('http://groovy.codehaus.or
g/')
My research tells me that I need to include NekoHTML in the classpath.
So I set up an environment variable CLASSPATH and it equals:
CLASSPATH=D:\TOOLS\nekohtml-1.9.18\src
I opened another cmd window and ran my test groovy script. I get the same error as above.
What should my CLASSPATH be set to refer to NekoHTML components with org.cyberneko.html.parsers.SAXParser?
You will need nekohtml-1.9.18.jar and xercesImpl-2.10.0.jar on your classpath.
Or you could just add a #Grab to the top of your script
#Grab( 'net.sourceforge.nekohtml:nekohtml:1.9.18' )
And groovy webtesting.groovy would fetch these dependencies for you. Of course, it depends how the script is being run

Running Groovy script from Gradle using GroovyShell: Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/cli/ParseException

I want to run a groovy command-line script from my Gradle build script.
I'm using this code in my Gradle script:
def groovyShell = new GroovyShell();
groovyShell.run(file('script.groovy'), ['arg1', 'arg2'] as String[])
Things work fine until my Groovy script (script.groovy) uses the CliBuilder class. Then I get the following exception:
org.codehaus.groovy.runtime.InvokerInvocationException: java.lang.NoClassDefFoundError: org/apache/commons/cli/ParseException
...
Caused by: java.lang.ClassNotFoundException: org.apache.commons.cli.ParseException
I found lots of people with similar problems and errors, but "the solution" was difficult to extract from the numerous posts I read. Lots of people suggested putting the commons-cli jar on the classpath, but doing so for the GroovyShell was not at all apparent to me. Also, I had already declared #Grapes and #Grab for my required libraries in the script.groovy, so it should have everything it needed.
Thanks to this unaccepted SO answer, I finally found what I needed to do:
//define our own configuration
configurations{
addToClassLoader
}
//List the dependencies that our shell scripts will require in their classLoader:
dependencies {
addToClassLoader group: 'commons-cli', name: 'commons-cli', version: '1.2'
}
//Now add those dependencies to the root classLoader:
URLClassLoader loader = GroovyObject.class.classLoader
configurations.addToClassLoader.each {File file ->
loader.addURL(file.toURL())
}
//And now no more exception when I run this:
def groovyShell = new GroovyShell();
groovyShell.run(file('script.groovy'), ['arg1', 'arg2'] as String[])
You can find more details about classLoaders and why this solution works in this forum post.
Happy scripting!
(Before you downvote me for answering my own question, read this)
The alternative to do this is the following:
buildScript {
repositories { mavenCentral() }
dependencies {
classpath "commons-cli:commons-cli:1.2"
}
}
def groovyShell = new GroovyShell()
....
This puts the commons-cli dependency on the classpath of the buildscript instead of on the classpath of the project to be built.

Resources