Creating and registering custom Groovy extension modules
A Groovy extension module allows you to add new methods to existing classes, including classes which are precompiled, like classes from the JDK.1 With extension modules, you can conveniently extend the behavior of an existing class without changing the definition of the class.
Groovy itself ships with a default extension module and it is because of this extension module that you are able to use code like the following:
1 2 3 |
|
The sum()
method is not defined in the ArrayList
class
At first glance, sum()
may look like an instance method but it is in fact a public
static
method with multiple
implementations found in the DefaultGroovyMethods
class, where many default extension methods are defined.
Groovy's default extension module adds a suite of extra methods to File
s, Collection
s, Map
s, String
s, primitive
arrays, and more.
Groovy's enhancements on the JDK
Learn more about Groovy's changes to the JDK by visiting their API documentation.
In addition to what Groovy offers by default, Martini also provides other extension modules intended to help you code and build your applications faster. These extension modules contain the so-called 'functions' – handy utility methods that help solve common application problems in just one line of code. But aside from the extension modules provided by Groovy and Martini, you can also add your own. Continue reading the following section to learn how.
Procedure
To define and register your own extension module, you must:
- Create a new project2 and then create the class which will contain your extension methods. You can create multiple classes if you want.
- Create the extension module descriptor file.
- Pack the files you have created in a JAR.
- Store the JAR in your Martini package's
lib
directory.
Alternatively, you can opt to keep your extension module classes (their source code) in the Martini package3
where you will use it so you won't have to create a JAR file; all you need is to place the descriptor file in the
META-INF/services
directory.
Reuse Groovy extension modules from other projects
Groovy extension modules are not just a Martini thing. You can grab the extension module JAR of another project and plug it to a Martini package so you can use it in Martini. Likewise, you can get a copy of your extension module JAR from Martini and use it for your projects outside of Martini (assuming it has no dependencies on Martini classes).
Creating the extension module's classes and methods
All you need to do is create a class containing the methods you want to add. These methods must:
- Have the modifiers
public
andstatic
- Have at least one parameter
- Ensure that the first parameter's type is also the class that will be extended
Check out other guides!
We recommend reading Hubert Klein Ikkink's (mrhaki) and Andre Steingress' blog posts about Groovy extension modules. Both articles thoroughly explain the process of creating a Groovy extension module.
To help you get started, here's an example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
|
Where's the public
modifier?
By default, Groovy considers classes and methods public. So you don’t have to use the public modifier everywhere something is public. Only if it’s not public should you put a visibility modifier.4
The class above defines two extension methods:
-
MathMethods.gcf(int, int)
An extra method for the
int
class (inferred from the first parameter's type) for finding the greatest common factor of two integers. -
MathMethods.gcf(int...)
An extra method for the
int[]
class (inferred from the first parameter's type) for finding the greatest common factor of an array of integers.
Common practices
When creating extension module classes, it is common practice to:
- Not define static and instance extension methods together in a single class
- Create separate extension modules per target type
Creating the descriptor file
In the META-INF/services
directory of your module archive or classpath, create the
org.codehaus.groovy.runtime.ExtensionModule
file. We will use this file to define the extension module, like so:
1 2 3 4 |
|
Multiple extension classes
You can add multiple extension classes on a single extension module. Simply delimit each class name with a comma.
If you want to add instance methods to the target type5, then use the extensionClasses
property; if you want
to add static methods instead, use the staticExtensionClasses
property.
Creating the JAR
Typically, the JAR file creation process is tied to the project's lifecycle. For those using build tools, this can be as simple as executing a single build command. As an alternative, you can also rely on Java's native commands to package a JAR for you, or use IDEs capable of producing JARs using an export function.
Usage
After moving the JAR or extension module descriptor file under your Martini package's META-INF/services
directory,
you may now use your extension methods.
To use instance extension methods (like that seen in this example), call the method on an instance of the first parameter's type, like so:
1 2 |
|
For static extension methods, you must call the method on the initial parameter's type (like you would normally call static methods); for example:
1 |
|
-
See extension modules. ↩
-
A separate project that does not reside in Martini. ↩
-
Particularly in the
code
directory. ↩ -
See public by default. ↩
-
The target type is the type of the extension method's first parameter. ↩