groovy.lang.MissingMethodException while trying to pass a closure as a parameter - groovy

I am new to groovy and am trying to pass a closure as a parameter to a method , below is my code , I am using Groovy 2.4
class Test
{
def testMethod()
{
def cl = {a,b -> println "a = "+${a}+" b = "+${b}}
testClosure(cl);
}
def testClosure(closure)
{
closure(5,2);
}
}
I am getting the below exception when i am trying to execute it ,
Caught: groovy.lang.MissingMethodException: No signature of method:
com.gr.practice.Test.$() is applicable for argument types:
(com.gr.practice.Test$_testMethod_closure1$_closure2) values:
[com.gr.practice.Test$_testMethod_closure1$_closure2#3e92efc3]
Possible solutions:
is(java.lang.Object),
any(),
any(groovy.lang.Closure),
use([Ljava.lang.Object;),
wait(),
dump()
groovy.lang.MissingMethodException: No signature of method:
com.gr.practice.Test.$() is applicable for argument types:
(com.gr.practice.Test$_testMethod_closure1$_closure2) values:
[com.gr.practice.Test$_testMethod_closure1$_closure2#3e92efc3]
Possible solutions:
is(java.lang.Object),
any(),
any(groovy.lang.Closure),
use([Ljava.lang.Object;),
wait(),
dump()
at com.gr.practice.Test$_testMethod_closure1.doCall(Test.groovy:10)
at com.gr.practice.Test.testClosure(Test.groovy:16)
at com.gr.practice.Test$testClosure$0.callCurrent(Unknown Source)
at com.gr.practice.Test.testMethod(Test.groovy:11)
at com.gr.practice.Test$testMethod.call(Unknown Source)
at com.gr.practice.main.run(main.groovy:7)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Could anyone please help ?

Your problem is println "a = "+${a}+" b = "+${b}. You probably want this:
println "a = ${a} b = ${b}"
Or:
println "a = " + a + " b = " + b
(the former is a better idea)

Related

Error in script to count the number of occurrences

I am entirely new to Groovy scripting and need help.
I tried the following script to count the number of lines that has a specific text occurrence.
Error observed:
groovy.lang.MissingMethodException: No signature of method: java.io.File.eachline() is applicable for argument types: (Hemanth_v1$_run_closure2) values: [Hemanth_v1$_run_closure2#10f39d0]
Possible solutions: eachLine(groovy.lang.Closure), eachLine(int, groovy.lang.Closure), eachLine(java.lang.String, groovy.lang.Closure), eachFile(groovy.lang.Closure), eachLine(java.lang.String, int, groovy.lang.Closure), eachFile(groovy.io.FileType, groovy.lang.Closure)
Script:
def file = new File('C:\\NE\\header.txt');
count = 0
def data1= file.filterLine { line ->
line.contains('smtpCus:');
}
//custom code by Hemanth
file.eachline { line, count ->
if (line.contains('Received:')) {
count++
}
}
There are two issues with the script you've shown to us:
there is a typo in file.eachline - it should be file.eachLine
in the closure passed to eachLine you increment a local variable count so the outer count remains 0 after the execution.
Here is what your script should look like:
def file = new File('C:\\NE\\header.txt')
count = 0
def data1 = file.filterLine { line ->
line.contains('smtpCus:')
}
//custom code by Hemanth
file.eachLine { line ->
if (line.contains('Received:')) {
count++
}
}
println count
Reading file as java.util.stream.Stream<T>
There is also one thing worth mentioning if it comes to reading files in Groovy (and Java in general). If you work with a huge file it's a good practice to load this file using Java Stream API - Files.lines(path)
import java.nio.file.Files
import java.nio.file.Paths
long counter = Files.lines(Paths.get('C:\\NE\\header.txt'))
.filter { line -> line.contains('Received:') }
.count()
println counter
Groovy methods use camel case. It should be eachLine() instead of eachline(). See if that helps!

How to sort elements in an array or just print them sorted?

I wrote the following Groovy code which returns an array of CIDR blocks in use throughout all 3 AWS regions we use, the results are populated to a Jenkins extended parameter:
def regions = ['us-west-2', 'us-east-1', 'eu-west-1']
def output = []
regions.each { region ->
def p = ['/usr/local/bin/aws', 'ec2', 'describe-vpcs', '--region', region].execute() | 'grep -w CidrBlock'.execute() | ['awk', '{print $2}'].execute() | ['tr', '-d', '"\\"\\|,\\|\\{\\|\\\\["'].execute() | 'uniq'.execute()
p.waitFor()
p.text.eachLine { line ->
output << line
}
}
output.each {
println it
}
The output of the code looks like so:
172.31.0.0/16
172.56.0.0/16
172.55.0.0/16
172.64.0.0/16
172.52.0.0/16
I would like to sort the output in a numeric way, can it be done?
Edit #1:
If I use ".sort()" I get the following error:
Caught: groovy.lang.MissingMethodException: No signature of method: java.lang.String.sort() is applicable for argument types: () values: []
Possible solutions: drop(int), tr(java.lang.CharSequence, java.lang.CharSequence), wait(), toSet(), size(), size()
groovy.lang.MissingMethodException: No signature of method: java.lang.String.sort() is applicable for argument types: () values: []
Possible solutions: drop(int), tr(java.lang.CharSequence, java.lang.CharSequence), wait(), toSet(), size(), size()
at populate_parameter_with_used_cidrs$_run_closure2.doCall(populate_parameter_with_used_cidrs.groovy:15)
at populate_parameter_with_used_cidrs.run(populate_parameter_with_used_cidrs.groovy:14)
Some general hints to your code first:
p.waitFor() is not necessary if you do p.text, as this waits for the process to finish first anyway.
To get a list of Strings for the lines of a multi-line String, you can simply use readLines().
To transform one list into another list you can use collect() or collectMany().
This would boil down your code to
def regions = ['us-west-2', 'us-east-1', 'eu-west-1']
def output = regions.collectMany { ['/usr/local/bin/aws', 'ec2', 'describe-vpcs', '--region', it].execute() | 'grep -w CidrBlock'.execute() | ['awk', '{print $2}'].execute() | ['tr', '-d', '"\\"\\|,\\|\\{\\|\\\\["'].execute() | 'uniq'.execute().text.readLines() }
output.each { println it }
And to get the number-aware sorting, you add to that
output = output.sort { a, b ->
def aparts = a.split('[./]').collect { it as short }
def bparts = b.split('[./]').collect { it as short }
(0..4).collect { aparts[it] <=> bparts[it] }.find() ?: 0
}
How about .sort()?
def list = ['172.31.0.0/16', '172.56.0.0/16', '172.55.0.0/16', '172.64.0.0/16', '172.52.0.0/16']
println list.sort()
As an option: to sort and remove duplicates
(output as SortedSet).each {
println it
}

Default parameter in closure

Looking at the groovy manual, I see that I should be able to use default parameters in closures, like so:
def closureWithTwoArgAndDefaultValue = { int a, int b=2 -> a+b }
assert closureWithTwoArgAndDefaultValue(1) == 3
However, running that in groovysh gives me the following error:
ERROR groovy.lang.MissingMethodException:
No signature of method: groovysh_evaluate.closureWithTwoArgAndDefaultValue() is applicable for argument types: (java.lang.Integer) values: [1]
Could somebody tell me why?
Try to omit def:
closureWithTwoArgAndDefaultValue = { int a, int b=2 -> a+b }
assert closureWithTwoArgAndDefaultValue(1) == 3
For further explanation, see here.

Groovy default method parameters

How to call the below method def to pass only interactionId, transactionId, awResponseFile, testMethodName and expectedNumberOfConsumers?
method def
void verifyPersistence(String interactionId, String transactionId,
File rawResponseFile, String testMethodName,
int expectedNumberOfDatasourceProductResponseRaws=1,
String dsProductName=datasourceSpec['creditreport.name'],
int expectedNumberOfDatasourceProductResponses=1,
int expectedNumberOfConsumers=1,
int expectedNumberOfAddresses=1 )
method call
verifyPersistence interactionId.persistedVersion(), transactionId,
results, testName.methodName, expectedNumberOfConsumers:8
Exception
groovy.lang.MissingMethodException: No signature of method: verifyPersistence() is applicable for argument types: (java.util.LinkedHashMap, java.lang.String, java.lang.String, java.io.File, java.lang.String) values: [[expectedNumberOfConsumers:8], 3130001030065, 10003000000890059, C:\results, multiple consumers contracts]
Possible solutions:
verifyPersistence(java.lang.String, java.lang.String, java.io.File, java.lang.String),
verifyPersistence(java.lang.String, java.lang.String, java.io.File, java.lang.String, int),
verifyPersistence(java.lang.String, java.lang.String, java.io.File, java.lang.String, int, java.lang.String),
verifyPersistence(java.lang.String, java.lang.String, java.io.File, java.lang.String, int, java.lang.String, int), verifyPersistence(java.lang.String, java.lang.String, java.io.File, java.lang.String, int, java.lang.String, int, int)
at HitmultipleconsumersPersistSpec.groovy:151)
When you include a map entry (key:value), they get automatically collected, put into a hashmap and passed as the first parameter. Groovy, right now, doesn't have named parameters. For that specific case, i think you are better using a map for that method:
def verifyPersistence(Map map) {
String interactionId = map.interactionId
String transactionId = map.transactionId
File rawResponseFile = map.rawResponseFile
String testMethodName = map.testMethodName
int expectedNumberOfDatasourceProductResponseRaws = map.expectedNumberOfDatasourceProductResponseRaws ?: 1
String dsProductName = map.dsProductName ?: datasourceSpec['creditreport.name']
int expectedNumberOfDatasourceProductResponses = map.expectedNumberOfDatasourceProductResponses ?: 1
int expectedNumberOfConsumers = map.expectedNumberOfConsumers ?: 1
int expectedNumberOfAddresses = map.expectedNumberOfAddresses ?: 1
}
verifyPersistence(
interactionId : interactionId.persistedVersion(),
transactionId : transactionId,
rawResponseFile : results,
expectedNumberOfDatasourceProductResponseRaws : 14,
expectedNumberOfConsumers:8
)
You obviously don't need to assign every parameter to a variable, you can simply use the map.field syntax. If you want it to be type checked, then i think you are better using an object to encapsulate the parameters.

groovy method that take closure with one or two arguments

I would like to write a method that take a Closure as argument and pass to it tow arguments, but who write that closure can specify one or two arguments as he prefer
I tried in this way:
def method(Closure c){
def firstValue = 'a'
def secondValue = 'b'
c(firstValue, secondValue);
}
//execute
method { a ->
println "I just need $a"
}
method { a, b ->
println "I need both $a and $b"
}
If I try to execute this code the result is:
Caught: groovy.lang.MissingMethodException: No signature of method: clos2$_run_closure1.call() is applicable for argument types: (java.lang.String, java.lang.String) values: [a, b]
Possible solutions: any(), any(), dump(), dump(), doCall(java.lang.Object), any(groovy.lang.Closure)
at clos2.method(clos2.groovy:4)
at clos2.run(clos2.groovy:11)
How can I do it?
You can ask for the maximumNumberOfParameters of the Closure before calling it:
def method(Closure c){
def firstValue = 'a'
def secondValue = 'b'
if (c.maximumNumberOfParameters == 1)
c(firstValue)
else
c(firstValue, secondValue)
}
//execute
method { a ->
println "I just need $a"
}
method { a, b ->
println "I need both $a and $b"
}
Output:
I just need a
I need both a and b
The simplest is to give it a default value:
method { a, b=nil ->
println "I just need $a"
}
You can also use an array:
method { Object[] a ->
println "I just need $a"
}

Resources