In order to prevent confusion with officialy supported mixin mechanisms that may be added to Groovy in the future, I have used the term 'gynamo' instead of 'mixin'. It is in essence trying to provide the same functionality.

Gynamo is a lightweight mechanism for extending classes with discrete packages of functionality similar to mixins in languages like Ruby.

Terms

To make things easier (hopefully) to understand, the following is a definition of terms used:

Example

class Square
{
	def size
}
import gynamo.*
class AreaGynamo extends Gynamo
{
	def getArea = {->
		return delegate.size * delegate.size
	}
}
import gynamo.*

Gynamo.gynamize(Square, AreaGynamo)

def s = new Square(size: 10)
assert s.area == 100

Hopefully that illustrates the point.

Download

You can also grab the buildable source from the SVN repository.

Gynamo is released under the same license terms as Groovy.

Documentation

All classes in the Gynamo library are in the package "gynamo".

Gynamos can contain fields (which will be public when injected) and methods (which Gynamos define as closures). All methods and properties are attached via ExpandoMetaClass so all the usual rules apply there.

Methods and properties are attached via the '=' operator so any existing methods or properties with a matching name will be overridden. This is something to watch out for.

Writing a Gynamo

A Gynamo is any class that extends the gynamo.Gynamo class. Gynamo inheritance is not supported, all Gynamos must directly extend the Gynamo class.

Methods (as closures) or fields to be injected must be accessible via getters. Groovy makes this too easy by generating getters for any fields that you don't specify the visiblity of.

import gynamo.*
class SomeGynamo extends Gynamo
{
	// Will become a public field on Gynamees
	def afield
	
	// Will become the method printSomething() on Gynamees.
	def printSomething = {->
		println "something"
	}
}

You can even add fields and methods statically to a class ...

import gynamo.*
class SomeGynamo extends Gynamo
{
	// Will become a public static field on the Gynamee's class
	static aStaticField
	
	// Will become the method aStaticMethod on the Gynamee's class.
	static aStaticMethod = {->
		// method code here
	}
}

Gynamizing

The Gynamo class defines the static method gynamize which takes a Gynamee class and a Gynamo class and performs the injection.

import gynamo.*
Gynamo.gynamize(GynameeClass, GynamoClass)

Or alternatively using categories ...

import gynamo.*

use (Gynamo) {
	GynameeClass.gynamize(GynamoClass)
}

Pre and Post Gynamize hooks

If your Gynamo needs to do anything before or after Gynamization of a class there are optional hooks for it

import gynamo.*
class SomeGynamo extends Gynamo
{
	void preGynamize(Class clazz)
	{
		// Could instrospect clazz and throw exceptions if there it shouldn't be Gynamized with this Gynamo
	}
	
	// ... some properties or methods to copy here ...
	
	void postGynamize(Class clazz)
	{
		// Could set any default values on clazz here or do anything else
	}
}

Gynamo Properties

Sometimes you want to add bean like properties to a Gynamee. This is a little awkward but you can make it work using the provided GynamoPropertyStorage class. Another caveat is that you have to define the getter and/or setter for each such property. Here is an example ...

import gynamo.*
class SomeGynamo extends Gynamo
{
	def getObjectProperty = {->
		return GynamoPropertyStorage[delegate].objectProperty
	}
	
	def setObjectProperty = {
		GynamoPropertyStorage[delegate].objectProperty = it
	}
	
	static getStaticProperty = {->
		return GynamoPropertyStorage[delegate].staticProperty
	}
	
	static setStaticProperty = {
		GynamoPropertyStorage[delegate].staticProperty = it
	}
}

GynamoPropertyStorage is pretty simple. It contains a synchronized WeakHashMap. Take a look at the source for details.

You would use the above like so ...

import gynamo.*

use(Gynamo) {
	SomeClass.gynamize(SomeGynamo) 
}

def o1 = new SomeClass()
def o2 = new SomeClass()

o1.objectProperty = "o1"
o2.objectProperty = "o2"

assert o1.objectProperty == "o1"
assert o1.objectProperty == "o2"

// Can't use property notation with static properties added dynamically due to groovy bug 
SomeClass.setStaticProperty("static")
assert SomeClass.getStaticProperty() == "static"

Gynamo dependencies

If you have a gynamo that depends on another Gynamee being injected then you can specify that with annotations ...

import gynamo.*
@GynamoDependency(SomeOtherGynamo)
class SomeGynamo extends Gynamo
{
	...
}

The @GynamoDependency annotation takes a single parameter of type Class which must be another Gynamo. The specified Gynamo will be injected automatically *before* this Gynamo gets injected. Therefore, the methods and fields of the dependency are available on the Gynamee at time of Gynamization.

If your Gynamo depends on multiple Gynamos, you can use the @GynamoDependencies annotation to specify a list of Gynamos that need to be injected before.

import gynamo.*
@GynamoDependencies([SomeOtherGynamo, SomeOtherOtherGynamo])
class SomeGynamo extends Gynamo
{
	...
}

*Note:* Be careful of circular dependencies. The dependency handling is pretty simple so if you do have a a circular dependency, your code will blow up with a StackOverflowError. If anyone has any suggestions on how this can be improved please let me know.