Reputation: 9082
I am working on a Java module that uses Groovy as a compile time dependency and I would like to add a method to my Java class Person
(Like the Groovy JDK) without writing Groovy code.
In Groovy I would achieve it like that
Person.meta.doSomething = { String param -> println "do something: ${param}" }
How can I do it using the Groovy API form Java?
EDIT 1:
I have implemented the following so far and I am almost there. I instantiate an Expando class for Person
and register a MethodClosure
that delegates the method call to a method in the class PersonDefaultMethods
.
ExpandoMetaClass expando = new ExpandoMetaClass (Person.class, true, false);
expando.registerInstanceMethod ("format", new MethodClosure (new PersonDefaultMethods(), "format"));
expando.initialize ();
The PersonDefaultMethods
contains the the implementation of the methods I declared in the Expando class.
public class PersonDefaultMethods {
public String format(String format) {
return this.toString(); // this one gets called
}
public String format(Person self, String format) { // but I want this method to be called
return self.getFirstname() + " " + self.getLastname();
}
}
When I know execute a Groovy script within this context I am able to call the format
method on a Person
instance but I am unable to access the delegate
like I usually can using a closure.
EDIT 2:
The approach of using a closure subclass or anonymous closure class fails in my implementation.
ExpandoMetaClass expando = new ExpandoMetaClass(Person.class, true, false);
expando.registerInstanceMethod("format", new Closure(this) {
@Override
public Object call(Object arguments) {
return super.call(arguments);
}
@Override
public Class[] getParameterTypes () {
return new Class[] { String.class};
}
});
expando.initialize ();
This does the job. Thank you.
Upvotes: 5
Views: 2494
Reputation: 6518
You can get the current meta class via GroovySystem.getMetaClassRegistry().getMetaClass(Person.class);
better. But to simulate the above you need to do several things by hand Groovy does for you in the background.
ExpandoMetaClass
(short EMC). If the metaclass from above is not an EMC, you will need to create one and register it in the registry: ExpandoMetaClass emc = new ExpandoMetaClass(Person.class)
. registerInstanceMethod
with either a String and Closure, or a MetaMethod. The variant above is the Closure version and will call the other one in the background.registerInstanceMethod
will be the name of the methodUpvotes: 3