Extension modules for extension methods
What is an extension method?
Since version 2.0, Groovy supports the notion of extension module. Basically, an extension module allows you to plugin extension methods to existing classes, just like regular Groovy does. For example, when you write:
The getText method doesn't exist on the File class. However, Groovy knows it because it is defined in a special class ResourceGroovyMethods (formely, the method was defined in DefaultGroovyMethods):
You may notice that the extension method is defined using a static method in a "helper" class (where various extension methods are defined). The first argument of the getText method corresponds to the receiver, while additional parameters correspond to the arguments of the extension method. So here, we are defining a method called getText on the File class (because the first argument is a File), which takes a single argument as a parameter (the encoding String).
Definining your own module
Thanks to improved modularity, Groovy 2 now adds support for your custom extension methods. For that, you only have to write two things:
- your extension class, just like DefaultGroovyMethods, IOGroovyMethods, ...
- a descriptor file for your module
Then you just need to pack your extension module into a jar file and add it to the classpath! Groovy will automatically recognize the module at startup.
Writing your extension class
As we saw before, adding methods to an existing class is as simple as writing a helper class which will only contain static methods. Imagine we want to add a method called reverseToUpperCase on the String class. This method would reverse the string then turn it to upper case. Then, you can write the following helper class:
That's all! Now imagine that you want to extend a class with a static method. For example, we would like to add an randomUUID() method to the String class which would return a random UUID string. Then, we must declare another extension class. The important thing to understand is that instance extension methods and static extension methods must be defined in two separate files. The only thing that will make a difference is the descriptor (see below). Then, the static extension helper class would look like this:
The module descriptor
For Groovy to be able to load your extension methods, you must declare your extension helper classes. You must create a file named org.codehaus.groovy.runtime.ExtensionModule into the META-INF/services directory:
The module descriptor requires 4 keys:
- moduleName : the name of your module
- moduleVersion: the version of your module. Note that version number is only used to check that you don't load the same module in two different versions.
- extensionClasses: the list of extension helper classes for instance methods. You can provide several classes, given that they are comma separated.
- staticExtensionClasses: the list of extension helper classes for static methods. You can provide several classes, given that they are comma separated.
Note that it is not required for a module to define both static helpers and instance helpers, and that you may add several classes to a single module. You can also extend different classes in a single module without problem. It is even possible to use different classes in a single extension class, but it is recommended to group extension methods into classes by feature set.
Technically, the previous description about how to add extension methods to an existing class is a user-friendly way of doing it, but Groovy doesn't force you to use this standard mechanism. If you want to, you can write your own extension module implementation class, given that a module returns a list of MetaMethods to be added to a class. However, implementing such a module is not easy, and won't be covered by this tutorial. If you need to do that, please refer to the org.codehaus.groovy.runtime.m12n.ExtensionModule and org.codehaus.groovy.runtime.m12n.ExtensionModuleRegistry classes.