dalew75
dalew75

Reputation: 99

Groovy: automatically extend all setters for properties

If I have a groovy class like this:

class WebSession{
    String firstName
    String lastName
    String email
}

I want to be able to use the automatic setters to set the value. For example:

WebSessionuser = new WebSession()
webSession.firstName = 'John'

But have the setter it calls do extra stuff, like log something or persist the object to cache.

How would I do this without having to define all the setters manually? So far I have something like this, but I can't quite get it working:

    webSession.properties.each{ key, value ->
        if ( key != 'class' ) {
            String methodName = "set${key.capitalize()}";
            WebSession.metaClass[key]."${methodName}" = { -> delegate
                System.out.println("Setting key: ${key}");
                webSession[key] = delegate;
            }
        }

    }

Also, I don't know if looping over the property names minus 'class' is hacky and there's a better way to get the declared fields.

Upvotes: 1

Views: 535

Answers (1)

Emmanuel Rosa
Emmanuel Rosa

Reputation: 9885

You can intercept all the getters and setters by implementing void setProperty(String, Object) and Object getProperty(String). Here's an example:

Example

def a = new WebSessionDecorator(new WebSession())

a.firstName = 'John'

println a.firstName

class WebSession {
    String firstName
    String lastName
    String email
}

class WebSessionDecorator {
    private WebSession delegate

    WebSessionDecorator(WebSession webSession) {
        this.delegate = webSession
    }

    void setProperty(String name, Object value) {
        println "LOG: Setting $name to $value"
        delegate.setProperty(name, value)        
    }

    def getProperty(String name) {
        println "LOG: Returning $name"
        delegate.getProperty(name)
    }
}

Output

The output looks like this:

LOG: Setting firstName to John
LOG: Returning firstName
John

Explanation

The WebSessionDecorator intercepts all property access, providing an opportunity for going whatever you want to do. Then, it delegates the property access to the actual WebSession.

I chose to go with a decorator in order to avoid recurring calls to getProperty() and setProperty(), and to make it possible to use the decorator only when applicable. For example, you may not want to use it in a unit test.

Upvotes: 2

Related Questions