views:

232

answers:

1

I'm trying to intercept a method call (afterInsert() of a domain class) in a Grails application. In doWithDynamicMethods closure of my plugin I have:

for (dc in application.domainClasses) {
    // What I'm basically doing is renaming method A to B
    // and creating a new method A with its own business logic
    // and a call to B() at the end

    def domainClass = dc.getClazz()
    def oldAfterInsert = domainClass.metaClass.afterInsert
    domainClass.metaClass."afterInsert_old" = oldAfterInsert

    dc.metaClass.afterInsert = {
        // New afterInsert() logic here

        // Call the old after insert
        delegate.afterInsert_old()
    }

}

But then I get this error:

No signature of method: static com.example.afterInsert_old() is applicable for argument types: () values: []

I've also tried to call it with dc.metaClass."afterInsert_old".invoke(delegate, new Object[0]) but then I get:

Caused by: groovy.lang.MissingMethodException: No signature of method: groovy.lang.ExpandoMetaClass$ExpandoMetaProperty.invoke() is applicable for argument types: (com.example.DomainName, [Ljava.lang.Object;) values: [com.example.DomainName : 115, []]

What am I doing wrong? How can I call a method that takes no arguments?

I know about AOP and have also seen the Grails Audit Logging plugin as an example. However, what it does is, as far as I know, add new user created methods that get triggered at the right time. I want to inject my code automatically so that the user doesn't have to worry about anything and I don't want to destroy his original afterInsert() (or whatever method it is) implementation.

Also, I'd like to do the same for exposed service methods in order to inject security into them. However, from what I've read it would not work because of the BeanWrapper and because the services are always reloaded. Can someone explain this better to me?

Thanks in advance.

+2  A: 

I don't think you need to rename the old method. You could do it like in this example:

for (dc in application.domainClasses) {
    // What I'm basically doing is renaming method A to B
    // and creating a new method A with its own business logic
    // and a call to B() at the end
    def domainClass = dc.getClazz()
    def savedAfterInsert = domainClass.metaClass.getMetaMethod('afterInsert', [] as Class[])
    domainClass.metaClass.afterInsert = {
        // New afterInsert() logic here

        // Call the old after insert
        savedAfterInsert.invoke(delegate)
    }

}

Just make sure that the getMetaMethod returns the correct method.

Daff