Method overloading in groovy - groovy

I am trying to take advantage of the convenience of groovy's scripting syntax to assign properties, but having trouble with a specific case. I must be missing something simple here. I define class A, B, C as so:
class A {
A() {
println "Constructed class A!"
}
}
class B {
B() {
println "Constructed class B!"
}
}
class C {
private member
C() {
println "Constructed class C!"
}
def setMember(A a) {
println "Called setMember(A)!"
member = a
}
def setMember(B b) {
println "Called setMember(B)!"
member = b
}
}
And then try the following calls in a script:
c = new C()
c.setMember(new A()) // works
c.member = new A() // works
c.setMember(new B()) // works
c.member = new B() // doesn't work!
The last assignment results in an error: 'Cannot cast object of class B to class A". Why doesn't it call the proper setMember method for class B like it does for class A?

The shortcut of using the dot notation for calling a property's setter method doesn't do type checking. Instead it seems to use the first entry in the list of methods with a given name and invoke it.
You can also read Pyrasun's extended comments on the shortcomings of Groovy's property handling.
If you want to bypass this (mis)behavior you have to call the setter directly, as Groovy supports type checking for method calls. Alternatively you could also access the field directly without a setter using
c.#member = new B()
or you do the type checking on your own in a single setter method:
def setMember(def param) {
if (param instanceof A) println "Called setMember(A)!"
if (param instanceof B) println "Called setMember(B)!"
member = param
}

Related

Creation of an instance with `with` block causes a type issue

I am using Groovy to create a package that I use in ReadyApi.
In a Groovy script test step, I do the following:
class B {
String value
boolean isSomething
}
class A {
String name
B propB
public A() {
this.name = "Maydan"
}
}
def x = (A) new A().with { propB = new B(value: "Abc", isSomething: true) }
And I get the following error:
org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'B#6c218cea' with class 'B' to class 'A'
error at line: 15
Does someone know why? It doesn't make any sense to me.
Kind regards.
PS: I would like to create an instance of class A (by using its parameterless constructor) and setting its field propB in a single statement
You need to return your A object from the .with closure. You may do it like that:
def x = (A) new A().with { propB = new B(value: "Abc", isSomething: true); return it}
but to me personally it looks a little bit odd. I would do it like that:
def x = new A(propB: new B(value: "Abc", isSomething: true))
The same effect, but more compact and readable. It doesn't require to change your A and B definitions, this "map constructor" works out of the box in Groovy, it will call your parameterless constructor and then assigns the necessary fields (propB in your case).

Why is the return type in Function<T, R> ignored in Groovy?

The following simple code explains my confusion:
class Main {
static void f(Function<Float, Float> c) {
println(c.apply(0.0f))
}
static void main(String[] args) {
Closure<String> c = {"hi"}
f(c)
}
}
I have no idea why the compiler does not complain that Closure<String> is not appropriate for Function<Float, Float>. Seems that I can pass anything to f().
the following code
import java.util.function.*
def c = {"result $it :: ${it.getClass()}"}
Function<Float, Float> f = c
println "f: ${f.getClass()} ${f instanceof Function}"
println "c: ${c.getClass()} ${c instanceof Function}"
println f.apply(0.1)
prints
f: class com.sun.proxy.$Proxy22 true
c: class ConsoleScript10$_run_closure1 false
result 0.1 :: class java.math.BigDecimal
groovy is dynamic - there is no type check unless you specify this (CompileStatic)
closure does not implement function. so, when you are assigning closure into function - groovy tries to delegate closure through a function interface. it will be dynamic even if you use compile static...

how can i assign a closure class with a closure property

I have a class something like this
class SomeClass () {
Closure instClos
SomeClass (Closure clos) { instClos = clos} //constructor
def call() {instClos()}
}
what i'd like to be able to do is do implicit Class constructor like this
SomeClass myInst = {println "hello there}
myInst()
but that doesn't work and throws cast exception. you can make this work by writing [] round the closure to call the constructor. but its not pretty
SomeClass myInst = [{println "hello there}] // or myInst = new ({println "hello there}
myInst()
is there a nice way to create the object through assignment and have that closure stored automatically on the created class instance?
feel i'm missing some groovy syntax here that would sort this (PS i'd prefer not having to extend Closure if i can avoid that )
based on the input provided so far i provided an extended script to show the various options. I tried to add an asType closure to Closure and try and call {...} as SomeClass - but if i tried that the asType is never called so groovy must be using another mechanism when you try a coercion
class SomeClass {
Closure instClos
SomeClass (Closure clos) {
println "\tSomeClass constructor: Will constructor called"
instClos = clos
}
def call() {
println "\tSomeClass.call: calling closure "
return (instClos() + "!")
}
SomeClass asType (Closure clos) {
new SomeClass (instClos: clos)
}
}
//this will call the map constructor - needs to be explicitly provided
SomeClass me = [{println "map style construction"; "echo"}]
assert me() == "echo!"
//use new to get class instance with constructor
me = new SomeClass ({println "new SomeClass () construction"; "echo"})
assert me() == "echo!"
//using layered closure approach - doesnt read well though
def someClos = {new SomeClass(it)}
def c = someClos {println "trying layered closure ";"echo"}
assert c() == "echo!"
//extending the Closure class to add a method
ExpandoMetaClass.enableGlobally()
Closure.metaClass.some = {
if (it == SomeClass) {
new SomeClass (delegate)
}
}
//this will call .some() on closure
me = {println "hello will using .some() "; "echo"}.some ( SomeClass)
assert me() == "echo!"
I'm not aware of anyway to auto-coerce a closure. Even though groovy has closure coercion, it works by changing the closure's type, but it's still a closure, and is not layered. Some ideas:
1. Constructor
class SomeClass {
Closure instClos
SomeClass (Closure clos) { instClos = clos} //constructor
def call() {instClos() + "!"}
}
def c = new SomeClass( { "echo" } )
assert c() == "echo!"
2. Map constructor
class SomeClass {
Closure instClos
def call() {instClos() + "!"}
}
SomeClass c = [instClos: { "echo" }]
assert c() == "echo!"
3. Closure metaprogramming
(Needs enableGlobally())
ExpandoMetaClass.enableGlobally()
Closure.metaClass.some = { new SomeClass(delegate) }
def c = { "echo" }.some()
assert c() == "echo!"
4. Another closure layering
class SomeClass {
Closure instClos
SomeClass (Closure clos) { instClos = clos} //constructor
def call() {instClos() + "!"}
}
def some = { new SomeClass(it) }
def c = some { "echo" }
assert c() == "echo!"
5. Override Closure's asType
ExpandoMetaClass.enableGlobally()
def asType = Closure.metaClass.asType
Closure.metaClass.asType = { Class c ->
(c == SomeClass) ? new SomeClass(delegate) : asType(c)
}
def c = { "echo" } as SomeClass
assert c() == "echo!"
If you have enough flexibility in your design you TRULY only need one method, SomeClass.call(), then you could specify it as an interface instead:
interface SomeClass {
def call()
}
Groovy long ago anticipated the case that Java 8 formalizes with the #FunctionalInterface annotation. If you assign a Groovy Closure to variable or formal parameter of interface type, where the interface has only one method (like SomeClass as defined above), the Groovy compiler will coerce the closure into an instance of that interface. So, given the interface declaration above, the following code:
SomeClass myInst = { println "hello there" }
myInst()
prints "hello there".

Groovy scope - how to access script variable in a method

I have a question about scoping rules in Groovy. In the following snippet, I have three variables, a has local scope, b has script scope, and c should get script scope as well using the #Field annotation.
#!/usr/bin/groovy
import groovy.transform.Field;
//println org.codehaus.groovy.runtime.InvokerHelper.getVersion()
def a = 42;
b = "Tea"
#Field def c = "Cheese"
void func()
{
// println a // MissingPropertyException
println b // prints "Tea"
println c // prints "Cheese" with groovy 2.1.2, MissingPropertyException with groovy 1.8.6
}
class Main
{
def method()
{
// println a // MissingPropertyException
// println b // MissingPropertyException
// println c // MissingPropertyException with both 1.8.6. and 2.1.2
}
}
func();
new Main().method();
I get MissingPropertyExceptions on the lines indicated with comments. The exceptions on a are expected, as that variable has local scope. But I would expect b to be accessible inside method() - it isn't.
#Field doesn't do anything in groovy 1.8.6, although after upgrading it works, so I guess that is an old bug. Nevertheless, c is inaccessible inside method() with either version.
So my questions are:
Why can't I access a variable annotated with #Field inside
method()?
How can I refer to a script variable inside method()?
When you have methods or statements outside of a class declaration in a groovy script, an implicit class is created. To answer your questions:
In your example, func() can access the field c because they are both members of the implicit class. The Main class is not, so it can't.
You need to pass a reference to the script variable to method(). One way is to pass the implicitly defined binding object, through which you can access all the script scope variables.
Example:
#!/usr/bin/groovy
import groovy.transform.Field;
//println org.codehaus.groovy.runtime.InvokerHelper.getVersion()
def a = 42;
b = "Tea"
#Field def c = "Cheese"
void func()
{
// println a // MissingPropertyException
println b // prints "Tea"
println c // prints "Cheese" with groovy 2.1.2, MissingPropertyException with groovy 1.8.6
}
class Main
{
def scriptObject
def binding
def method()
{
// println a // MissingPropertyException
println binding.b
println scriptObject.c
}
}
func();
new Main(scriptObject: this, binding: binding).method();
This script and Main are generated as two separate classes inside the same file.
As Main is not an internal class of the Script class, it cannot see the java.lang.Object c field inside the script class.
You would either have to explicitly wrap this script in a class with a static main( args ) method (and an internal Main class) or you would need to pass an instance of the script class to the method like: Main.method( this )
This is the sort of thing that the above script generates:
class Script032034034 {
Object c
Script032034034() {
c = 'Cheese'
}
Object run() {
Object a = 42
b = 'Tea'
func()
new Main().method()
}
void func() {
println b
println c
}
}
class Main {
Object method() {
}
}

In groovy, is there a way to check if an object has a given method?

Assuming that I have an object someObj of indeterminate type, I'd like to do something like:
def value = someObj.someMethod()
Where there's no guarantee that 'someObj' implements the someMethod() method, and if it doesn't, just return null.
Is there anything like that in Groovy, or do I need to wrap that in an if-statement with an instanceof check?
Use respondsTo
class Foo {
String prop
def bar() { "bar" }
def bar(String name) { "bar $name" }
}
def f = new Foo()
// Does f have a no-arg bar method
if (f.metaClass.respondsTo(f, "bar")) {
// do stuff
}
// Does f have a bar method that takes a String param
if (f.metaClass.respondsTo(f, "bar", String)) {
// do stuff
}
Just implement methodMissing in your class:
class Foo {
def methodMissing(String name, args) { return null; }
}
And then, every time you try to invoke a method that doesn't exist, you will get a null value.
def foo = new Foo();
assert foo.someMethod(), null
For more information, take a look here: http://groovy.codehaus.org/Using+methodMissing+and+propertyMissing
You should be able to do something like:
SomeObj.metaClass.getMetaMethod("someMethod")
Or you can fall back to the good old Java reflection API.
You can achieve this by using getMetaMethod together with the safe navigation operator ?.:
def str = "foo"
def num = 42
def methodName = "length"
def args = [] as Object[]
assert 3 == str.metaClass.getMetaMethod(methodName, args)?.invoke(str, args);
assert null == num.metaClass.getMetaMethod(methodName, args)?.invoke(num, args);
if class :
MyClass.metaClass.methods*.name.any{it=='myMethod'}//true if exist
if object :
myObj.class.metaClass.methods*.name.any{it=='myMethod'}//true if exist
In very concise way you can use this:
if(someObj.&methodName){
//it means someObj has the method
}

Resources