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.
A method is in Groovy is defined with a return type or with the def keyword. Methods can receive any number of arguments. It's not necessary that the types are explicitly defined when defining the arguments. Modifiers such as public, private and protected can be added.
In Groovy, we can add a method named call to a class and then invoke the method without using the name call . We would simply just type the parentheses and optional arguments on an object instance. Groovy calls this the call operator: () . This can be especially useful in for example a DSL written with Groovy.
A Groovy class is a collection of data and the methods that operate on that data. Together, the data and methods of a class are used to represent some real world object from the problem domain. A class in Groovy declares the state (data) and the behavior of objects defined by that class.
Groovy scripts can use any Java classes. They can be compiled to Java bytecode (in . class files) that can be invoked from normal Java classes. The Groovy compiler, groovyc, compiles both Groovy scripts and Java source files, however some Java syntax (such as nested classes) is not supported yet.
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 methodIf you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With