开发者

grails metaprogramming

My understanding is that there are two obvious places in a Grails app where one can do meta-programming:

  1. The init closure of Bootstrap.groovy
  2. The doWithDynamicMethods closure 开发者_运维知识库of a plugin

The meta-programming I'm referring to here should be visible throughout the application, typical examples include adding (or replacing) methods of 3rd party classes.

String.metaClass.myCustomMethod = { /* implementation omitted */ }

The disadvantage of (1), is that the metaprogramming won't be applied when the application is dynamically reloaded. The disadvantage of (2) is that I need to create and maintain an entire plugin just for the sake of a little metaprogramming.

Is there a better place to do this kind of metaprogramming?

Update

Following Ted's suggestion below, I added the following class to src/groovy

package groovy.runtime.metaclass.java.lang

/**
 * Adds custom methods to the String class
 */
class StringMetaClass extends DelegatingMetaClass {

    StringMetaClass(MetaClass meta) {
        super(meta)
    }

    Object invokeMethod(Object object, String method, Object[] arguments) {
        if (method == 'hasGroovy') {
            object ==~ /.*[Gg]roovy.*/
        } else {
            super.invokeMethod object, method, arguments
        }
    }
}

Then restarted the app and ran the following code in the Grails console:

assert 'mrhaki loves Groovy'.hasGroovy()

I got the following exception

groovy.lang.MissingMethodException: No signature of method:
java.lang.String.hasGroovy() is applicable for argument types: () values: []

Am I doing something wrong or is there a reason this doesn't work in a Grails app?


Check out the Delegating MetaClass, it's part of groovy and makes your metaclass changes part of the metaclass that's used on every instance of that class right from the start. It operates on a simple convention and even works outside of grails.


Depending on your use case, Groovy AST transformations are a third option. AST transformation are modifications of the bytecode at compile time. They are available since Groovy 1.6 and have been improved a lot in Groovy 1.7. Esp. ASTBuilder is a very elegant way.

Be aware that using AST within Grails might require some modifications to the build. The classes performing the AST must be compiled before the classes that are subject to AST. This could be easily done by hooking into the "CompileStart" event in scripts/_Events.groovy and precompile the Transformation first.


You can use the DelegatingMetaClass solution, but it needs to be packaged in a JAR file and then added to the lib directory.

Create a new directory with the following Gradle build file:

apply plugin: 'groovy'
repositories.mavenCentral()
dependencies { groovy: 'org.codehaus.groovy:groovy-all:1.8.6' }

In the src/main/groovy directory you can place the StringMetaClass source code. With $ gradle jar you can create a JAR file and then copy it to the lib directory of your Grails application.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜