How to use multiple classes in multiple files in scripts? - groovy

I need to make a standalone Groovy script that does not require compilation and runs without Groovy installed. It works well, but it fails to recognize any other script than the main script.
My folder structure is the following:
libs\
groovy-all-2.4.3.jar
ivy-2.4.0.jar
src\
makeRelease.groovy
ReleaseHelper.groovy
I am launching the script this way from the src folder:
java -cp "../libs/*" makeRelease.groovy
makeRelease looks like this:
public class makeRelease {
public static void main(String... args) {
new ReleaseHelper()
...
}
}
When run this is the output:
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
src\makeRelease.groovy: 5: unable to resolve class ReleaseHelper
How can I include other classes (that reside in separate files) in such portable scripts?

I think that it is easier than you think:
libs\
groovy-all-2.4.3.jar
src\
main.groovy
Greeter.groovy
Where main.groovy
public class Main {
public static void main(args) {
println 'Main script starting...'
def greeter = new Greeter()
greeter.sayHello()
}
}
and Greeter.groovy
class Greeter {
def sayHello() {
println 'Hello!'
}
}
Simply add to the classpath the folders where you have the classes in separate files:
java -cp .;..\libs\groovy-all-2.4.3.jar groovy.ui.GroovyMain main.groovy
The above yields:
Main script starting...
Hello!

Related

Cucumber CLI Main skipping the feature files

I want to execute cucumber tests from cucumber CLI instead of Maven.
I have below code in my Runner class:
import io.cucumber.core.cli.Main;
public class Runner {
public static void main(String[] args) {
Main.main(new String[]{"-g", "src/test/java/com/company/project/stepdefinitions", "-t", "Regression", "src/test/resources/features"});
}
}
When I execute it, it doesn't run any tests -
0 Scenarios
0 Steps
0m0.163s
Any Idea what am I missing ? If I remove the tag then it detects the feature file but says corresponding stepdefinition is missing.
Main.main(new String[]{"-g", "src/test/java/com/company/project/stepdefinitions/module1/Stepmodule1","src/test/resources/features/module1/ValidateModule1.feature"});
Undefined scenarios:
file:///C:/Users/.../src/test/resources/features/module1/ValidateModule1.feature:5 # To Test Module1
1 Scenarios (1 undefined)
1 Steps (1 undefined)
0m0.228s
Am I calling main function in CLI with wrong parameters?
Kind Regards,
Abhi
Thanks for the suggestions.
The below syntax worked for me for giving glue and feature files in a standalone Java class.
import io.cucumber.core.cli.Main;
public class Runner {
public static void main(String[] args) {
Main.main(new String[]{"-g", "com.company.project.stepdefinitions","-t", "#Regression","-p", "com.aventstack.extentreports.cucumber.adapter.ExtentCucumberAdapter:", "src/main/resources/features/"});
}
}

Running Groovy test cases with JUnit 5

Maybe this is very simple, but I couldn't find any examples on the web:
I'd like to use JUnit 5 to run a unit test implemented as a Groovy class. My current setup seems to launch JUnit 5, but fail to detect the test case. IntelliJ recognizes the test, but fails to run it. If I add a Java unit test, it is launched correctly.
Here's what I have now:
Project structure
src
main
groovy
# production code
test
groovy
UnitTest.groovy
build.gradle
...
build.gradle
plugins {
id 'groovy'
}
dependencies {
compile localGroovy()
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.1.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.1.1'
}
test {
useJUnitPlatform()
}
UnitTest.groovy
import org.junit.jupiter.api.Test
class UnitTest {
#Test
def shouldDoStuff() {
throw new RuntimeException()
}
}
I'm using Gradle 4.10.
Any ideas?
JUnit requires all testing method to use return type void. Groovy's def keyword is compiled to an Object type, so your method compiles to something like this in Java:
import org.junit.jupiter.api.Test
public class UnitTest {
#Test
Object shouldDoStuff() {
throw new RuntimeException();
}
}
If you try this out as a Java test, it won't find the test case neither. The solution is very simple - replace def with void and your Groovy
test case will be executed correctly.
src/test/groovy/UnitTest.groovy
import org.junit.jupiter.api.Test
class UnitTest {
#Test
void shouldDoStuff() {
throw new RuntimeException()
}
}
Demo:

How to use import inside a dynamically loaded groovy file

I am trying to come up with a way for my users to supply plugins into the main groovy application by dynamically loading their source file. But their groovy file contains import statements and I don't know how to make them work even with an apparently good classpath.
The main application is a shell script, bin/top.sh:
#!/bin/bash
groovy-2.4.1/bin/groovy -cp lib lib/Top.groovy
The lib/Top.groovy class:
public class Top {
public static void main(String[] args) {
ClassLoader parent = getClass().getClassLoader()
GroovyClassLoader loader = new GroovyClassLoader(parent)
Class groovyClass = loader.parseClass(new File("UserPlugin.groovy"))
GroovyObject groovyObject = (GroovyObject) groovyClass.newInstance()
groovyObject.invokeMethod("run",args)
}
}
The user class UserPlugin.groovy:
// The following import can be found in the classpath
// passed by the shell script (under lib/, next to Top.groovy)
import Lib
class UserPlugin {
def UserPlugin() {
Lib lib = new Lib()
}
def run(String [] args) {
println("Running with: "+args)
}
}
And the lib/Lib.groovy:
class Lib {
def Lib() {
println("Lib")
}
}
When I run with bin/top.sh, I get: UserPlugin.groovy: 3: unable to resolve class Lib
When I add lib to the class loader like so loader.addClasspath('lib'), it's rather catastrophic:
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
General error during class generation: java.lang.NoClassDefFoundError: groovy/lang/GroovyObject
java.lang.RuntimeException: java.lang.NoClassDefFoundError: groovy/lang/GroovyObject
at org.codehaus.groovy.control.CompilationUnit.convertUncaughtExceptionToCompilationError(CompilationUnit.java:1088)
How can this work while keeping it all scripted and not compiled? Is this even possible?
Sorry I don't have time to find the bug but I think the problem is with the setting of the context classloader. GroovyShell.run takes care of that for you which I recommend over replicating that code.
Top.groovy
public class Top {
public static void main(String[] args) {
new GroovyShell().run(new File("UserPlugin.groovy"), args)
}
}
If you're willing to make Top.groovy a script rather than class then you can do this:
Top.groovy
run(new File("UserPlugin.groovy"), args)
The UserPlugin.groovy then needs to be either a class (with a main method) or a script to use the standard Groovy calling logic.

Load groovy classes/scripts dynamically without compilation?

I have a set of groovy scripts in package hierarchy. I have 1 main script, from which I want to call others. For example I have these scripts (with public classes/interfaces of the same name in them):
package.MainScript
package.MyInterface;
package.utils.MyInterfaceImpl1 //implements MyInterface
package.utils.MyInterfaceImpl2 //implements MyInterface
Is there a way to call one script from the other without knowing called class name at compile time? I mean to do something like dynamic class loading like:
class MainScript {
public static void main (String[] args) {
MyInterface instance = Class.forName("package.utils.Util1");
}
}
Yeah! Groovy is a dynamic language. You can create class instance dynamically.
package.MyInterface
class MyInterfaceImpl1 {
def greet() {
"Hello"
}
}
package.MyInterface
class MyInterfaceImpl2 {
def greet() {
"Hi!"
}
}
def name = 'MyInterfaceImpl1' // Choose whatever you want at runtime
def className = Class.forName("MyInterface.$name")
def instance = className.newInstance()
assert instance.greet() == 'Hello'

How to get classpath in Groovy?

How can I get current value of CLASSPATH in Groovy?
Shameless stolen from http://blog.blindgaenger.net/print_groovys_classpath_for_debugging.html
This code will go up the classloader tree and printout each classloader and the associated classpath.
def printClassPath(classLoader) {
println "$classLoader"
classLoader.getURLs().each {url->
println "- ${url.toString()}"
}
if (classLoader.parent) {
printClassPath(classLoader.parent)
}
}
printClassPath this.class.classLoader
You should be able to get the classpath from the SystemClassLoader, providing it is an URLClassLoader:
URL[] classPathUrls = ClassLoader.getSystemClassLoader().getURLs();
java.class.path doesn't work properly, at least in Groovy 2.1.6 (Mac OS X 10.6.8).
HelloWorld.groovy:
public class HelloWorld {
public static void main(def args) {
System.out.println( "Hello, world!\n");
System.out.println(System.getenv("CLASSPATH")+"\n");
System.out.println(System.getProperty("java.class.path"));
}
}
Then
export CLASSPATH=/etc
groovy -classpath /usr HelloWorld.groovy
Result:
Hello, World!
/etc
/Applications/groovy-2.1.6/lib/groovy-2.1.6.jar
Now, this is HelloWorld.java: (I had to change it a bit as Groovy and Java are not 100% compatible):
public class HelloWorld {
public static void main(String args[]) {
System.out.println( "Hello, world!\n");
System.out.println(System.getenv("CLASSPATH")+"\n");
System.out.println(System.getProperty("java.class.path"));
}
}
Now:
javac HelloWorld.java
export CLASSPATH=/etc
java -classpath /usr HelloWorld
Result:
Exception in thread "main" java.lang.NoClassDefFoundError: HelloWorld
Caused by: java.lang.ClassNotFoundException: HelloWorld
etc. ...................
Then:
java -classpath /usr:. HelloWorld
Result:
Hello, world!
/etc
/usr:.
I'll update if I find out how to make it work in Groovy...
Get the CLASSPATH and files if you want in the those CLASSPATH if needed you can view it
System.getProperty("java.class.path", ".").tokenize(File.pathSeparator).each {
println it
}
This doesn't work?
System.getProperty('java.class.path')
def classpath = System.properties["java.class.path"]

Resources