1

In groovy 1.8.6, I was trying to do something like this:

class Greeter {
    def sayHello() {
        this.metaClass.greeting = { System.out.println "Hello!" }
        greeting()
    }
}

new Greeter().sayHello()

This didn't work:

groovy.lang.MissingPropertyException: No such property: greeting for class: groovy.lang.MetaClassImpl

After a bit of trying, I found that passing a reference to self to the method did work. So, basically what I came up with was this:

class Greeter {
    def sayHello(self) {
        assert this == self
        // assert this.metaClass == self.metaClass

        self.metaClass.greeting = { System.out.println "Hello!" }
        greeting()
    }
}

def greeter = new Greeter()
greeter.sayHello(greeter)

The strangest thing is that the assert this == self actually passes, which means they are the same instance... right? The default toString also seems to confirm this.

On the other hand, the assert this.metaClass == self.metaClass fails:

assert this.metaClass == self.metaClass
            |         |  |    |
            |         |  |    org.codehaus.groovy.runtime.HandleMetaClass@50c69133[groovy.lang.MetaClassImpl@50c69133[class Greeter]]
            |         |  Greeter@1c66d4b3
            |         false
            groovy.lang.MetaClassImpl@50c69133[class Greeter] 

Why is self.metaClass wrapped in a HandleMetaClass, while this.metaClass isn't? Also, how can the first example be made to work without passing in a reference to self?

Pelle Wielinga
  • 307
  • 2
  • 8
  • I encountered the same problem:http://stackoverflow.com/questions/34449587/groovy-this-metaclass-versus-instance-metaclass. Have you figured out the this.metaClass problem? – Guocheng Dec 25 '15 at 08:56

2 Answers2

1

I figured out the 2 questions:

  • groovy.lang.MissingPropertyException: No such property: greeting for class: groovy.lang.MetaClassImpl

  • why this.metaClass == self.metaClass

See this link: https://stackoverflow.com/a/45407488/42769

Adeel Ansari
  • 39,541
  • 12
  • 93
  • 133
Guocheng
  • 543
  • 3
  • 15
0

You can implement methodMissing in the class as below to answer your last question:

class Greeter {
    def sayHello() {
        //this.metaClass.greeting = { System.out.println "Hello!" }
        greeting()
        goodNight()
    }

    def methodMissing(String name, args){
        if(name == 'greeting'){
            println "Hello!" 
        } else
            println "Good Night"
    }
}

new Greeter().sayHello()

Also note that == in groovy actually means equals() (that is value comparison) if you want to compare identity then is() can be used like

a.is(b) //Corresponds to == in Java
a == b //Corresponds to equals() in Java

UPDATE
Can use metaClass as below

Greeter.metaClass.greeting = { println "Hello"}
def greet = new Greeter()

//or
//greet.metaClass.greeting = { println "Hello"}

greet.sayHello()
dmahapatro
  • 49,365
  • 7
  • 88
  • 117
  • Thanks. Not sure why I didn't use methodMissing in the first place. Something to do with inner classes I think, but now it works. Didn't know about a.is(b), although assert this.is(self) still succeeds. – Pelle Wielinga Aug 28 '13 at 21:23
  • @PelleWielinga I prefer metaClass if I need to test or create tests immediately. To answer your first question see my updates. – dmahapatro Aug 28 '13 at 21:27
  • Greeter.metaClass.greeting defines it statically, which was a problem for me. greet.metaClass.greeting works, but this.metaClass.greeting not, which is still a mystery to me. – Pelle Wielinga Aug 28 '13 at 21:45
  • @PelleWielinga Nope, `Greeter.metaClass.greeting={..}` should not define it as static. For static methods, `Greeter.metaClass.'static'.greeting={..}` is used. – dmahapatro Aug 28 '13 at 21:56
  • Oh right, the method itself is not static, but it is defined for all future (and past?) instances. My methods vary from instance to instance, which I have now solved with a Map which is referenced from methodMissing. I'll try to find an example which is more closely related to my actual problem next time :) – Pelle Wielinga Aug 28 '13 at 22:09