Music, software, life… and stuff.
[ Twitter ] [ GitHub ] [ Linked In ]
I’m excited to be presenting a GR8Conf EU this year. This will be my first time at GR8 Conf and I’m looking forward to meeting some of the Groovy community that I’ve not had the opportunity to meet before.
I’ll be presenting on Geb, as both an introduction for the uninitiated and to discuss the new features that have appeared in the last few months. It will be an interesting change to present this material to a crowd already comfortable with Groovy; quite different to my upcoming session at SeleniumConf.
Of course, I’ll also be there representing Gradleware and helping Peter give a 3 hour Gradle Bootcamp that will get anybody up and running with Gradle. I’ll also be doing another (new) Gradle session on releasing software. This will be a tutorial style presentation that will arm you with everything you need to build, test and release open source software to Maven Central with Gradle. There will also be a dive into the Spock and Geb builds to look at how they managing building and testing Grails plugins as part of their builds and automating their release.
Hope to see you there!
Posted: Apr 3rd, 2012 @ 8:17 pm
Tags: #software #groovy #conference
I recently put out a new plugin for Grails that brings something like view models to Grails applications. An interesting feature of this plugin is that it supports direct object instantiation with implicit autowiring. You might think that Grails already support this, but it doesn’t. Currently, you can directly instantiate domain objects and get autowiring but you can’t write a constructor and use it here.
Groovy has had the ability to fiddle with a class’s constructors via EMC for a while.
class Thing {
def i
Thing() { i = 1 }
}
assert new Thing().i == 1
Thing.metaClass.constructor = { -> i = 2 }
assert new Thing().i == 2
Trying to augment existing constructors is a bit trickier though. Using the standard EMC API of setting a constructor property on the meta class, there is no way to access the constructor that is being replaced. To do this you have to dig a bit deeper.
For the view models plugin I needed to invoke the real constructor, then do some stuff to the new instance. My solution revolves around the registerInstanceMethod(groovy.lang.MetaMethod method) method of ExpandoMetaClass. After some digging through Groovy, I found that the technique above of setting a constructor property on the meta class boils down to just attaching an instance MetaMethod with a method name of <init> which is the name Groovy uses for constructors. So what we can do is subclass groovy.lang.MetaMethod to get our custom behaviour, which looks like this…
package grails.plugin.viewmodels.constructor;
import java.lang.InstantiationException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import groovy.lang.MetaMethod;
import org.codehaus.groovy.reflection.CachedClass;
import org.codehaus.groovy.reflection.ReflectionCache;
public class DecoratingMetaConstructor<T> extends MetaMethod {
final private Constructor<T> constructor;
final private ConstructionDecorator<T> decorator;
public DecoratingMetaConstructor(Constructor<T> constructor, ConstructionDecorator<T> decorator) {
super(decorator.getSignature(constructor));
this.constructor = constructor;
this.decorator = decorator;
}
public Constructor<T> getConstructor() {
return constructor;
}
public int getModifiers() {
return constructor.getModifiers();
}
public String getName() {
return "<init>";
}
public Class<T> getReturnType() {
return constructor.getDeclaringClass();
}
public CachedClass getDeclaringClass() {
return ReflectionCache.getCachedClass(constructor.getDeclaringClass());
}
public Object invoke(Object object, Object[] arguments) {
Object[] transformedArgs = decorator.transformArgs(arguments);
T instance = instantiate(transformedArgs);
decorator.decorate(instance, arguments, transformedArgs);
return instance;
}
protected T instantiate(Object[] arguments) {
try {
return decorator.transformConstructor(constructor).newInstance(arguments);
} catch (InstantiationException e) {
throw new RuntimeException("Failed to invoke constructor " + constructor + " with args: " + arguments, e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Failed to invoke constructor " + constructor + " with args: " + arguments, e);
} catch (InvocationTargetException e) {
throw new RuntimeException("Failed to invoke constructor " + constructor + " with args: " + arguments, e);
}
}
}
A lot of that is just satisfying the MetaMethod methods. What’s of interest to us is that we take a constructor object, and a decorator which is an interface that we provide…
package grails.plugin.viewmodels.constructor;
import java.lang.reflect.Constructor;
public interface ConstructionDecorator<T> {
public Object[] transformArgs(Object[] args);
public void decorate(T instance, Object[] originalArgs, Object[] transformedArgs);
public Class<?>[] getSignature(Constructor<T> constructor);
public Constructor<T> transformConstructor(Constructor<T> constructor);
}
The decorator can supply a different set of args for the actual Constructor to those that were given to the invocation, supply a different Constructor instance to use at instantiation time and/or do something with the instance after it has been created.
We can use this mechanism to write a construction decorator that performs autowiring…
package grails.plugin.viewmodels.constructor;
import java.lang.reflect.Constructor;
import org.springframework.context.ApplicationContext;
public class AutowiringConstructionDecorator<T> extends ConstructionDecoratorSupport<T> {
final private Autowirer autowirer;
public AutowiringConstructionDecorator(ApplicationContext applicationContext) {
this(new Autowirer(applicationContext));
}
public AutowiringConstructionDecorator(Autowirer autowirer) {
this.autowirer = autowirer;
}
public void decorate(T instance, Object[] givenArgs, Object[] transformedArgs) {
autowirer.autowire(instance);
}
}
The Autowirer takes care of the actual autowiring details, which aren’t of much interest here (see the class here if you want).
So we can now take a class, and make all of it’s constructors implicitly perform autowiring by doing something like this…
def autowiringDecorator = new AutowiringConstructionDecorator(grailsApplication.mainContext)
for (constructor in MyThing.constructors) {
MyThing.metaClass.registerInstanceMethod(new DecoratingMetaConstructor(constructor, autowiringDecorator))
}
Interestingly, I was able to use the same decoration mechanism to enable hot reloading support by obtaining the newest version of the constructor from the class loader in the Grails application that has the newest version of the class…
package grails.plugin.viewmodels.constructor;
import java.lang.reflect.Constructor;
class ReloadCapableConstructionDecorator<T> extends ConstructionDecoratorSupport<T> {
private final ClassLoader classLoader;
public ReloadCapableConstructionDecorator(ClassLoader classLoader) {
this.classLoader = classLoader;
}
public Constructor<T> transformConstructor(Constructor<T> constructor) {
try {
Class<T> originalClassVersion = constructor.getDeclaringClass();
Class<T> newestClassVersion = (Class<T>)classLoader.loadClass(originalClassVersion.getName());
return newestClassVersion.getConstructor(constructor.getParameterTypes());
} catch (NoSuchMethodException e) {
return constructor;
} catch (ClassNotFoundException e) {
return constructor;
}
}
}
The details of why this is needed isn’t worth going into now, what’s important is the fact that you could do some rather interesting stuff here.
If you find you have the need to decorate existing constructors as opposed to completely replacing them, it’s probably worth taking a look at what’s in the view-models plugin and either stealing it verbatim or adapting to your own purposes.
The relavant code and gory details can be found here.
Posted: Mar 4th, 2011 @ 3:54 pm