views:

135

answers:

1

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?

+1  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
}
Christoph Metzendorf