Question

I'm trying to change the behaviour of the constructor of a groovy class by replacing a method in that class which is used to set a property but the properties are not getting set with the expected values.

class TestClass {

    def noParam
    def withParam

    TestClass() {
        noParam = noParam()
        withParam = withParam('second test')
    }

    def noParam() {
        return 'first test'
    }

    def withParam(param) {
        return param
    }

}

TestClass.metaClass.withParam =  { param -> 'pass' }
TestClass.metaClass.noParam = {-> 'pass' }

def test = new TestClass()

assert test.withParam('dummy') == 'pass' //passes
assert test.withParam == 'pass' // fails
assert test.noParam() == 'pass' // passes
assert test.noParam == 'pass' // fails
Was it helpful?

Solution

Groovy is not using your metaclass overrides in the TestClass constructor when it executes the noParam and withParam methods. In fact, if you type the parameter in your withParam method, the 2nd assert will also fail.

class TestClass {

    def noParam
    def withParam

    TestClass() {
        noParam = noParam()
        withParam = withParam('second test')
        println "in the constructor: noParam = $noParam, withParam = $withParam"
    }

    def noParam() {
        return 'first test'
    }

    def withParam(String param) {
        return param
    }
}

TestClass.metaClass.withParam = { String param -> 'pass' }
TestClass.metaClass.noParam = {-> 'pass' }

def test = new TestClass()

assert test.withParam('dummy') == 'pass'
assert test.withParam  == 'pass' // this fails now too!
assert test.noParam() == 'pass'
assert test.noParam == 'pass' // this fails

Here's the output: in the constructor: noParam = first test, withParam = second test

test.withParam and test.noParam are actually calling test.getWithParam() and test.getNoParam() - they are returning the property values set in the constructor.

test.withParam('dummy') and test.noParam() are calling your metaclass method and returning "pass".

As far as why groovy does not use the metaclass method in your constructor, I'm not sure... I couldn't find anything in the metaclass documentation...

Maybe you could use static methods instead?

class TestClass {

    def noParam
    def withParam

    TestClass() {
        noParam = TestClass.noParam()
        withParam = TestClass.withParam('second test')
        println "in the constructor: noParam = $noParam, withParam = $withParam"
    }

    static def noParam() {
        return 'first test'
    }

    static def withParam(String param) {
        return param
    }
}

TestClass.metaClass.'static'.withParam = { String param -> 'pass' }
TestClass.metaClass.'static'.noParam = {-> 'pass' }

def test = new TestClass()

assert test.withParam('dummy') == 'pass'
assert test.withParam  == 'pass' // passes!
assert test.noParam() == 'pass'
assert test.noParam == 'pass' // passes!

Here's the output: in the constructor: noParam = pass, withParam = pass

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top