I'm trying to understand what is happening when I get errors like "groovy.lang.MissingMethodException: No signature of method: Three.method() is applicable for argument types: "
b = "Tea"
class Three
{
String myVar1, myVar2, myVar3, myVar4, myVar5, myVar6
def method(myVar1,myVar2,myVar3,myVar4,myVar5,myVar6)
{
try {
println myVar1, myVar2, myVar3, myVar4, myVar5, myVar6
} catch (groovy.lang.MissingPropertyException e) {
println "error caught"
}
}
}
try {
new Three().method(myVar1:b);
} catch (groovy.lang.MissingPropertyException e) {
println "error caught"
}
try {
new Three().method(myVar1=b);
} catch (groovy.lang.MissingPropertyException e) {
println "error caught"
}
try {
new Three().method(b);
} catch (groovy.lang.MissingPropertyException e) {
println "error caught"
}
I think that you're mixing different concepts... by default groovy classes has two default constructor, the default with no params and the map based constructor which works as follows:
def three = new Three(myVar1:'a',myVar2:'b',myVar3:'c')
println three.myVar1 // prints a
println three.myVar2 // prints b
println three.myVar3 // prints c
However in the case of the methods there isn't this default behavior and due you can not use this kind of invocation and you've to fit the signature of the method, in your case the method expects 6 arguments and you're trying to invoke it passing a map this is why you're getting a missingMethodException, because there is no method with this signature inside your class.
In your case you only have one method method() with 6 parameters with not implicit type so you've to invoke it like this:
three.method(1,'kdk','asasd',2323,'rrr',['a','b'])
// or like this
three.method(1,'kdk','asasd',2323,'rrr','b')
// or like this
three.method(1,2,3,4,5,6)
// ...
Note that in your code there is another error, you are invoking println erroneously inside method()... use this:
println "$myVar1 $myVar2 $myVar3 $myVar4 $myVar5 $myVar6"
instead of:
println myVar1, myVar2, myVar3, myVar4, myVar5, myVar6
Hope this helps,
Related
Is there a way to skip MissingPropertyException while using GroovyShell.evaluate?
def sharedData = new Binding()
def shell = new GroovyShell(sharedData)
shell.evaluate("a=5; b=1") // works fine
// How to not get MissingPropertyException, or silently ignore property 'a'
shell.evaluate("a; b=1") // MissingPropertyException for 'a'
I know about the Expando solution, is there a way to do it without defining a class?
A very minimal approach would be to override Binding.getVariable.
Note that this is very straight forward: "all exceptions" are ignored - you might want to have better logging or more accurate error handling.
import groovy.lang.*
class NoOpBinding extends Binding {
#Override
Object getVariable(String name) {
try {
return super.getVariable(name)
}
catch (Throwable t) {
println "Ignoring variable=`$name`"
return null
}
}
}
def shell = new GroovyShell(new NoOpBinding())
shell.evaluate("a; b=1") // MissingPropertyException for 'a'
// → Ignoring variable=`a`
println shell.getVariable('b')
// → 1
You could do something like this:
def binding = [:].withDefault { }
def shell = new GroovyShell(binding as Binding)
shell.evaluate 'a; b=1'
I have a simple script, which runs and works:
println testReturn()
String testReturn() {
def str = /asdf/
return str
}
If I change it to this, however, I see an error when I run it:
println testReturn()
String testReturn() {
return /asdf/
}
Error:
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
test.groovy: 6: unexpected token: / # line 6, column 12.
return /asdf/
^
1 error
Does anyone know why I have to define a slash-escaped string before returning it?
It seems to me that the return statement is treated like other function calls in groovy 2.x and that slashy strings do not work well with paren-less function calls.
An example:
println /asdf/ // fails
println(/asdf/) // works
println testReturn()
String testReturn() {
/asdf/ //works - implicit return
}
String btestReturn() {
return /asdf/ // fails
}
String testReturn() {
return(/asdf/) //works
}
in my book this is unexpected behavior and a restriction of the groovy parser.
In groovy 3 (or more specifically in this case, groovy 3.0.0-alpha-3), the parser has been rewritten and the following code:
println /asdf/ // fails
println(/asdf/) // works
println testReturn1()
println testReturn2()
println testReturn3()
String testReturn1() {
/asdf/ // works
}
String testReturn2() {
return /asdf/ // works
}
String testReturn3() {
return(/asdf/) // works
}
gives the somewhat more informative error:
Caught: groovy.lang.MissingPropertyException: No such property: println for class: solution
groovy.lang.MissingPropertyException: No such property: println for class: solution
at solution.run(solution.groovy:1)
which tells us that without parens, groovy can not determine if println is a property or a method call. Removing that first line makes the above code work under groovy 3.x.
I need to intercept method calls on predefined Java classes. For example, lets say I need to intercept String class split method, how do I do this?
I tried this which works, but I doesn’t want end user to change their code by wrapping their calls in with proxy block.
Is there any way this can be achieved with Groovy?
If what you want to do is intercept a call to a specific method you can do something like this...
// intercept calls to the split method on java.lang.String
String.metaClass.split = { String arg ->
// do whatever you want to do
}
If what you want to do is intercept a call to a specific method and do some stuff in addition to invoking the original (like to wrap the real method with some of your own logic) you can do something like this:
// get a reference to the original method...
def originalSplit = String.metaClass.getMetaMethod('split', [String] as Class[])
// now add your own version of the method to the meta class...
String.metaClass.split = { String arg ->
// do something before invoking the original...
// invoke the original...
def result = originalSplit.invoke(delegate, arg)
// do something after invoking the original...
// return the result of invoking the original
result
}
I hope that helps.
you want to use MetaClass for that see doc
ExpandoMetaClass.enableGlobally()
//call 'enableGlobally' method before adding to supplied class
String.metaClass.split = { regex ->
println "calling split from $delegate with $regex"
delegate.split regex, 22
}
To intercept all method calls in a class override Groovy's invokeMethod. Example:
class Test {}
Test.metaClass.foo = {"foo() called"}
Test.metaClass.static.bar = {"bar() called"}
Test.metaClass.invokeMethod = { name, args ->
handleInterception(name, args, delegate, false)
}
Test.metaClass.static.invokeMethod = { name, args ->
handleInterception(name, args, delegate, true)
}
def handleInterception(name, args, delegate, isStatic) {
def effDelegate = isStatic ? delegate : delegate.class
println ">> Entering ${delegate.class.name}.$name() with args: $args"
def metaMethod = effDelegate.metaClass.getMetaMethod(name, args)
if (!metaMethod) {
println "-- Method not found: $name($args)"
return
}
try {
def result = metaMethod.invoke(delegate, args)
println "<< Leaving ${delegate.class.name}.$name() with result: $result"
return result
} catch (ex) {
println "-- Exception occurred in $name: $ex.message"
throw ex
}
}
new Test().foo("1", 2)
Test.bar(2)
new Test().onTheFly(3)
Code taken from Roshan Dawrani's post at groovyconsole.appspot.com.
Output:
>> Entering Test.foo() with args: [1, 2]
-- Method not found: foo([1, 2])
>> Entering java.lang.Class.bar() with args: [2]
<< Leaving java.lang.Class.bar() with result: bar() called
>> Entering Test.onTheFly() with args: [3]
-- Method not found: onTheFly([3])
Other options:
Custom MetaClass implementing invokeMethod
Implementing the Interceptor Interface. Read more in this tutorial
I ran into a bad chunk of code today that equates to this:
[["asdf"]].each {String str -> println str}
println (["asdf"] as String)
Put this into groovy console (groovysh) and you'll see this come out:
asdf
[asdf]
Can anyone explain why there's a difference in the outputs?
Groovy will unwrap a List if it means it will fit into the types you have defined in your closure.
If you don't define the type (or set it as List), it will behave as you expect:
// Both print '[a]'
[['a']].each { it -> println it }
[['a']].each { List it -> println it }
If however you define a type, it will attempt to unwrap the list and apply the contents to the defined parameters, so:
// Prints 'a'
[['a']].each { String it -> println it }
Think of it like varargs in java, or calling the closure with closure( *it ) in Groovy
It actually comes in pretty useful as you can do things like:
// Tokenize the strings into 2 element lists, then call each with these
// elements in separate variables
['a=b', 'b=c']*.tokenize( '=' )
.each { key, value ->
println "$key = $value"
}
The first output
I don't know for sure, but it seems as though Groovy will try to apply the closure to a single element of a list, iff there is only one.
Note that this:
[["asdf"]].each {String str -> println str }
is equivalent to this:
Closure c = { String s -> println s }
c(["asdf"])
and that these tests suggest the empirical evidence:
Closure c = { String s -> println s }
println "c test"
try { c(["asdf","def"]) } catch(Exception ex) { println "no" }
try { c(123) } catch(Exception ex) { println "no" }
try { c([]) } catch(Exception ex) { println "no" }
// this works:
try { c(["asdf"]) } catch(Exception ex) { println "no" }
Closure d = { Integer i -> println i }
println "d test"
try { d([22,33]) } catch(Exception ex) { println "no" }
try { d("abc") } catch(Exception ex) { println "no" }
try { d([]) } catch(Exception ex) { println "no" }
// this works:
try { d([22]) } catch(Exception ex) { println "no" }
The second output
Simply note that this:
println (["asdf"] as String)
is likely equivalent to this:
List<String> list = ["asdf"]
println list.toString()
Is it possible to add a property or a method to an object dynamically in Groovy? This is what I have tried so far:
class Greet {
def name
Greet(who) { name = who[0].toUpperCase() + [1..-1] }
def salute() { println "Hello $name!" }
}
g = new Greet('world') // create object
g.salute() // Output "Hello World!"
g.bye = { println "Goodbye, $name" }
g.bye()
But I get the following exception:
Hello World!
Caught: groovy.lang.MissingPropertyException: No such property: bye for class: Greet
Possible solutions: name
at test.run(greet.groovy:11)
If you just want to add the bye() method to the single instance g of the class Greet, you need to do:
g.metaClass.bye = { println "Goodbye, $name" }
g.bye()
Otherwise, to add bye() to all instance of Greet (from now on), call
Greet.metaClass.bye = { println "Goodbye, $name" }
But you'd need to do this before you create an instance of the Greet class
Here is a page on the per-instance metaClass
And here is the page on MetaClasses in general
Also, there's a bug in your constructor. You're missing who from infront of your [1..-1] and if the constructor is passed a String of less than 2 characters in length, it will throw an exception
A better version might be:
Greet( String who ) {
name = who.inject( '' ) { String s, String c ->
s += s ? c.toLowerCase() : c.toUpperCase()
}
}
As metioned in the comments,
Greet( String who ) {
name = who.capitalize()
}
is the proper way