Java class inside the gradle build file fails - groovy

leftShift is deprecated in Gradle now.
I am trying to add a java class initialization inside the gradle build file like below:
task javaClassInGradleTask {
doLast {
class Myclass {
public void message() {
System.out.println("this is message from java class");
}
}
Myclass testObject = new Myclass();
testObject.message();
}
}
and I am trying to run the file:
gradle javaClassInGradleTask
My error result is below
FAILURE: Build failed with an exception.
* Where:
Build file '/Users/folder/build.gradle' line: 3
What went wrong:
Could not compile build file '/Users/folder/build.gradle'.
startup failed:
build file '/Users/folder/build.gradle': 3: Class definition not expected here. Please define the class at an appropriate place or perhaps try using a block/Closure instead. at line: 3 column: 2. File: BuildScript # line 3, column 2.
class Myclass {
^
1 error
Try: Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
Get more help at https://help.gradle.org
BUILD FAILED in 0s
But when I try to add the class using leftShift it works well.
Any idea to add class inside the gradle file?

It doesn't work for both doLast and <<. Try:
task javaClassInGradleTask {
doLast {
Myclass testObject = new Myclass()
testObject.message();
}
}
class Myclass {
public void message() {
System.out.println("this is message from java class");
}
}

Related

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 multiple classes in multiple files in scripts?

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!

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.

SoapUI/Groovy - Class defined but getting NoClassDefFoundError error

I am using Soap UI (Free version) v4.6.4. One of the test steps in my test case is to declare a class, which should be referred further in other groovy test steps; create instances and such. But to start with I tried the following in test step named ts01:
class SomeClass {
private String name
public SomeClass(String name) {
this.name = name
}
public print() {
log.info "SomeClass.print - " + this.name
}
}
// After the class definition, in the same groovy script
context.project = "myproject"
context.scinst = new SomeClass("hello")
log.info context
When I run this test step separately, I get the following error popup:
java.lang.NoClassDefFoundError: Could not initialize class SomeClass
error at line: XX
and randomly popping another error:
java.lang.ExceptionInInitializerError
When I run this test step as part of the test case, it runs but context.scinst is not available.
What am I missing? Why is SomeClass not available even though it is defined?
Your help is highly appreciated.
Thanks
Vivek Ragunathan

SLF4J groovy annotation compilation error. 'log' was found in a static scope but doesn't refer to a local variable, static field or class

I've been staring at this block of code for a good hour trying to figure out why the log isn't being picked up at compile time. I'm using gradle to build and have dependencies listed as such:
apply plugin: 'groovy'
repositories {
mavenCentral()
}
dependencies {
compile 'org.codehaus.groovy:groovy:2.2.1'
compile 'org.slf4j:slf4j-api:1.7.6'
provided 'org.projectlombok:lombok:1.12.4'
runtime 'ch.qos.logback:logback-core:1.1.1'
runtime 'ch.qos.logback:logback-classic:1.1.1'
testCompile 'junit:junit:4.11'
}
My 'code block' is a class called FilesUtil annotated with #groovy.logging.util.SLF4J which contains a single static method that utilizes the log variable as the annotation javadoc suggests
import groovy.util.logging.Slf4j
import java.nio.file.FileVisitResult
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.SimpleFileVisitor
import java.nio.file.attribute.BasicFileAttributes
import static java.nio.file.FileVisitResult.CONTINUE;
#Slf4j
class FilesUtil {
def static deleteDirectory(Path path) {
Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
#Override
public FileVisitResult visitFile(Path file,
BasicFileAttributes attrs) throws IOException {
log.trace("deleting file: $file")
System.out.println("Deleting file: " + file)
Files.delete(file);
log.trace("deleted file: $file")
return CONTINUE;
}
#Override
public FileVisitResult postVisitDirectory(Path dir,
IOException exc) throws IOException {
if (exc == null) {
log.trace("deleting directory: $dir")
Files.delete(dir);
log.trace("deleted directory: $dir")
return CONTINUE;
} else {
throw exc;
}
}
})
}
}
Upon calling gradlew build (using the gradle wrapper) i get 4 similar errors like the following:
startup failed:
C:\Users\Macindows\IdeaProjects\corporate-git\subprojects\core\src\main\groovy\com\thenaglecode\corporategit\core\util\files\FilesUtil.groovy: 26:
Apparent variable 'log' was found in a static scope but doesn't refer to a local variable, static field or class. Possible causes:
You attempted to reference a variable in the binding or an instance variable from a static context.
You misspelled a classname or statically imported field. Please check the spelling.
You attempted to use a method 'log' but left out brackets in a place not allowed by the grammar.
# line 26, column 17.
log.trace("deleting file: $file")
^
Where's Wally? (the mistake I can't find... Waldo for you American folk)
Because you have an internal anonymous class it seems to be not seeing the generated log variable. If you change log.trace to FilesUtil.log.trace it seems to work.
Or if you use a Map as a proxy for SimpleFileVisitor it seems to work as well:
Files.walkFileTree(path, [ visitFile: { Path file, BasicFileAttributes attrs ->
log.trace("deleting file: $file")
System.out.println("Deleting file: " + file)
//Files.delete(file);
log.trace("deleted file: $file")
return CONTINUE;
},
postVisitDirectory: { Path dir, IOException exc ->
if (exc == null) {
log.trace("deleting directory: $dir")
//Files.delete(dir);
log.trace("deleted directory: $dir")
return CONTINUE;
} else {
throw exc;
}
} ] as SimpleFileVisitor )
Not sure of the underlying cause or if it's a bug at the moment...not got much time to think atm ;-)

Resources