EightBitBoy
EightBitBoy

Reputation: 683

Access a property inside invokeMethod() implemented in a trait

The following Groovy trait implements the GroovyInterceptable interface to allow execution of code before and after method calls.

trait Bar implements GroovyInterceptable {
    def bar = "bar"

    @Override
    invokeMethod(String name, Object args) {
        System.out.println(bar)
        metaClass.getMetaMethod(name, args).invoke(this, args)
    }

    def doSomething() {
    }
}

The following class implements the trait Bar.

class Foo implements Bar {
}

Have a look at the following code.

def foo = new Foo()
foo.doSomething()

The call to doSomething() is being intercepted by invokeMethod(). A java.lang.StackOverflowError occurs because accessing the property bar inside invokeMethod() implicitly makes a call to the getter of bar which in turn is intercepted by invokeMethod() just trying to access bar again.

How can I access a class property inside invokeMethod without calling this property's getter or setter?

In combination with the trait using this.@bar to access the property does not work.

The code metaClass.getMetaMethod(name, args).invoke(this, args) to invoke the intercepted method could be incorrect although it works when using the trait logic directly inside a class.

Edit for Solution:

The accepted answer contributed by user Opal works like a charm in a script environment. Since the trait is part of a larger project and defined in its own file I made it work like this:

package com.example.project

trait Bar implements GroovyInterceptable {
    def bar = "bar"

    @Override
    invokeMethod(String name, Object args) {
        System.out.println(this.com_example_project_Bar__bar)
        metaClass.getMetaMethod(name, args).invoke(this, args)
    }

    def doSomething() {
    }
}

Upvotes: 1

Views: 341

Answers (1)

Opal
Opal

Reputation: 84784

It turns out that there's no need to use @ for direct field access:

trait Bar implements GroovyInterceptable {
    def bar = "bar"

    @Override
    invokeMethod(String name, Object args) {
        System.out.println(Bar__bar)
        metaClass.getMetaMethod(name, args).invoke(this, args)
    }

    def doSomething() {
    }
}

class Foo implements Bar {
}

def foo = new Foo()
foo.doSomething()

Upvotes: 2

Related Questions