I have created two groovy scripts as below. One script has a class which is instantiated in the other script. Both are in default package.
When I'm trying to run ImportGpsData.groovy I'm getting the following exception...
Caught: java.lang.ExceptionInInitializerError
java.lang.ExceptionInInitializerError
at ImportGpsData$_run_closure1.doCall(ImportGpsData.groovy:10)
at ImportGpsData.run(ImportGpsData.groovy:6)
Caused by: java.lang.RuntimeException: No suitable ClassLoader found for grab
at DateParser.<clinit>(DateParser.groovy)
... 2 more
ImportGpsData.groovy
def file = new File('fells_loop.gpx')
def slurper = new XmlSlurper()
def gpx = slurper.parse(file)
gpx.rte.rtept.each {
println it.#lat
println it.#lon
def parser = new DateParser()
println parser.parse(it.time.toString())
}
Dateparser.groovy
#Grapes(
#Grab(group='joda-time', module='joda-time', version='2.3')
)
import org.joda.time.DateTime
import org.joda.time.format.DateTimeFormat
class DateParser {
def String parse(time){
def printableTime = new DateTime(time)
def format = DateTimeFormat.forPattern('MM/dd/yyyy - hh:mm aa')
return printableTime.toString(format)
}
}
I've found some other StackOverFlow questions that dealt with No Suitable classloader found for grab error. One answer suggested using #GrabConfig(systemClassLoader=true) inside #Grapes statement however adding it is resulting in compilation error, I'm getting error unexpected token # in line two.
#Grapes([
#Grab(group='joda-time', module='joda-time', version='2.3')
#GrabConfig( systemClassLoader=true )
])
Above way of using it gave unexpected token # found in line 3...
Adding a comma before #GrabConfig is giving the below error
Multiple markers at this line
- Groovy:Invalid duplicate class definition of class DateParser : The source F:\GroovyEclipses\src\DateParser.groovy contains at least two definitions of the class DateParser.
- General error during conversion: No suitable ClassLoader found for grab java.lang.RuntimeException: No suitable ClassLoader found for grab
After further analysis, I have figured that I'm getting this error when ever I user #Grapes and #Grab in any of my scripts. However I have to use them to work with joda-time.
Not sure if you were able to resolve this, if not then try to compile the class file first:
groovyc Dateparser.groovy
and then do
groovy ImportGpsData.groovy
should work.
Related
I need to compare dates in pipeline. And this is hilarious, the following code works ok in Groovy script console in Jenkins but not in a pipeline:
def created = new Date().parse("yyyyMMdd", "20191012")
def now = new Date().minus(30)
println created
println now
if (now > created) {
println "blah"
} else {
println "foo"
}
In the pipeline this gives me the following output:
hudson.remoting.ProxyException: groovy.lang.MissingMethodException: No signature of method: java.util.Date.parse() is applicable for argument types: (java.lang.String, java.lang.String) values: [yyyyMMdd, 20191017]
Possible solutions: parse(java.lang.String, java.lang.String), parse(java.lang.String), parse(java.lang.String, java.lang.String, java.util.TimeZone), wait(), clone(), any()
I tried to change new Date().parse to Date.parse but then it exists with:
org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: No such static method found: staticMethod java.util.Date parse java.lang.String java.lang.String
How am I supposed to compare dates then?
EDIT: Rework using LocalDate
import java.time.LocalDate
import java.time.format.DateTimeFormatter
def due = 15
def creation_date = "20191012"
def dateFormat = DateTimeFormatter.ofPattern("yyyyMMdd")
def now = LocalDate.now().format(dateFormat);
def creation = LocalDate.parse(creation_date, dateFormat)
if (LocalDate.parse(now, dateFormat).minusDays(due) > creation) {
println "blah"
} else {
println "foo"
}
Works at Groovy console, does not work in pipeline, throws an error:
an exception which occurred:
in field org.jenkinsci.plugins.pipeline.modeldefinition.withscript.WithScriptScript.script
in object org.jenkinsci.plugins.pipeline.modeldefinition.agent.impl.LabelScript#55030b9c
in field groovy.lang.Closure.delegate
in object org.jenkinsci.plugins.workflow.cps.CpsClosure2#23e9719e
in field groovy.lang.Closure.delegate
in object org.jenkinsci.plugins.workflow.cps.CpsClosure2#165471ce
in field org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.closures
in object org.jenkinsci.plugins.workflow.cps.CpsThreadGroup#124c8a1d
in object org.jenkinsci.plugins.workflow.cps.CpsThreadGroup#124c8a1d
Caused: java.io.NotSerializableException: java.time.format.DateTimeFormatter
I'm now totally puzzled how to deal with it...
EDIT2: SOLUTION
It appears that the code was pasted into pipeline without 'def' determiners. By trial and error I narrowed down that it was required to have at least def dateFormat other vars were not required to have that. Looks like all serializable variables need to be defined via 'def'.
I'm leaving that as it is so maybe sb will benefit from it.
I want to use for scripting external Groovy Scripts.
To not copy a lot of code, I want to share classes.
I have:
- external_test.groovy
- Input.groovy
Running the external_test.groovy in Intellij works.
Input is a simple class:
package helpers
class Input {
String serviceConfig
String httpMethod
String path
LinkedHashMap headers = [:]
String payload
Boolean hasResponseJson
}
When the script is executed by Camunda, it cannot find the class:
import helpers.Input
...
And throws an Exception:
unable to resolve class helpers.Input # line 16, column 9. new helpers.Input(serviceConfig: "camundaService", ^ 1 error
It is listed in the Deployment:
Do I miss something or is this not supported?
I found a post in the Camunda forum, that helped me to solve this:
https://forum.camunda.org/t/groovy-files-cant-invoke-methods-in-other-groovy-files-which-are-part-of-same-deployment/7750/5
Here is the solution (that is not really satisfying - as it needs a lot of boilerplate code):
static def getScript(fileName, execution) {
def processDefinitionId = execution.getProcessDefinitionId()
def deploymentId = execution.getProcessEngineServices().getRepositoryService().getProcessDefinition(processDefinitionId).getDeploymentId()
def resource = execution.getProcessEngineServices().getRepositoryService().getResourceAsStream(deploymentId, fileName)
def scannerResource = new Scanner(resource, 'UTF-8')
def resourceAsString = scannerResource.useDelimiter('\\Z').next()
scannerResource.close()
GroovyShell shell = new GroovyShell()
return shell.parse(resourceAsString)
}
def helper = getScript("helpers/helper_classes.groovy", execution)
helper.myFunction("hello")
Trying to read data from excel file and save it in Test suite properties, but getting this error (Using SOAP UI 5.1.3)
//This is the code
import java.io.*
import jxl.*
def file =new File("D:\\GroovyTest\\Example.xls")
def wb=Workbook.getWorkbook(file)
def sheet=wb.getSheet("Sheet1")
r=sheet.getRows()
for(int i=1;i<2;i++)
{
Cell c1=sheet.getCell(0,i)
testRunner.testCase.testSuite.addProperty("CityName"+i)
String cityName =c1.getContents()
testRunner.testCase.testSuite.setProperty("CityName"+i,cityName)
testRunner.runTestStepByName("GetSupplierByCity")
}
this is Error:
Error: groovy.lang.MissingMethodException: No signature of method: com.eviware.soapui.impl.wsdl.WsdlTestSuite.setProperty() is applicable for argument types: (java.lang.String, java.lang.String) values: [CityName1, New York] Possible solutions: getProperty(java.lang.String), addProperty(java.lang.String), hasProperty(java.lang.String), hasProperty(java.lang.String), getProject(), getProperties() error at line: 12
You are very close to get it.
As the error says, there is no such method setProperty.
In order to set either new property or modify existing property, use just setPropertyValue method.
So, all you need to do is simple. Remove below statement from your code.
testRunner.testCase.testSuite.addProperty("CityName"+i)
And change below statement
From:
testRunner.testCase.testSuite.setProperty("CityName"+i,cityName)
To:
testRunner.testCase.testSuite.setPropertyValue("CityName"+i,cityName)
The Error in the Question was generated by the following code
package ian.eg.learn
class ReadXMLfile {
def customers = new XmlSlurper().parse(new File("C:\\Users\\IBM_ADMIN
\\Documents\\customers.xml"))
for (customer in customers.corporate.customer){
println "${customer.#name} works for ${customer.#company}"
}
}
I am using a regular "for" and I don't see why the compiler is having a problem
I don't know what version of Groovy you're using so the exact error message could vary, but you cannot just write statements like that anywhere in your class, so the compiler expects something else in place of your for statement.
Example:
class Xxx {
println("yoo")
}
Gives:
unexpected token: println # line 2, column 3.
println("yoo")
^
You need to move that code in a method, or an init block... anywhere but not directly in class body.
Is it possible to create class definitions within a groovy script?
I have a simple script example
class HelloWorld {
def name
def greet() {
"Hello ${name}"
}
}
def helloWorld = new HelloWorld()
helloWorld.name = "Groovy"
println helloWorld.greet()
but I get error like this
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
Script1.groovy: 1: Class definition not expected here. Please define the class at an appropriate place or perhaps try using a block/Closure instead. at line: 1 column: 1. File: Script1.groovy # line 1, column 1.
class HelloWorld {
^
1 error
at org.codehaus.groovy.control.ErrorCollector.failIfErrors(ErrorCollector.java:309) ~[groovy-all-2.4.3.jar:2.4.3]
at org.codehaus.groovy.control.CompilationUnit.applyToSourceUnits(CompilationUnit.java:943) ~[groovy-all-2.4.3.jar:2.4.3]
at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:590) ~[groovy-all-2.4.3.jar:2.4.3]
at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:566) ~[groovy-all-2.4.3.jar:2.4.3]
at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:543) ~[groovy-all-2.4.3.jar:2.4.3]
at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:297) ~[groovy-all-2.4.3.jar:2.4.3]
at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:267) ~[groovy-all-2.4.3.jar:2.4.3]
at groovy.lang.GroovyShell.parseClass(GroovyShell.java:692) ~[groovy-all-2.4.3.jar:2.4.3]
at groovy.lang.GroovyShell.parse(GroovyShell.java:704) ~[groovy-all-2.4.3.jar:2.4.3]
at groovy.lang.GroovyShell.parse(GroovyShell.java:740) ~[groovy-all-2.4.3.jar:2.4.3]
at groovy.lang.GroovyShell.parse(GroovyShell.java:731) ~[groovy-all-2.4.3.jar:2.4.3
This code works fine. You can see for yourself here.
Yes, in general it's normal to create class definitions within a script.
I'm not able to reproduce your error, and you don't say how you're running this code. I'm guessing you're trying to use a Groovy script to configure some product (Mule has this feature, for instance). Your problem would seem to be specific to the thing you're trying to configure.
If I try to run the script in groovysh I get "Unknown property" when it tries to define the helloWorld variable using def.
In groovyconsole it works fine, as Dónal says.
If I take your code and put it in a file called HelloWorld.groovy and run that from the command line:
groovy HelloWorld.groovy
then I get
C:\Users\ndh\HelloWorld.groovy: 1: Invalid duplicate class definition of class HelloWorld : The source C:\Users\ndh\HelloWorld.groovy contains at least two definitions of the class HelloWorld.
One of the classes is an explicit generated class using the class statement, the other is a class generated from the script body based on the file name. Solutions are to change the file name or to change the class name.
# line 1, column 1.
class HelloWorld {
^
1 error
Changing the name of the file to notHelloWorld.groovy works:
c:\Users\ndh>groovy notHelloWorld.groovy
Hello Groovy
but this is not your problem because the stacktrace shows your filename to be Script1.
When I write a script I put the main logic at the top and put helper functions and class definitions toward the bottom. That's just how I organize the code for readability, though.