Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding methods to a class using Groovy in Java

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.

like image 797
saw303 Avatar asked Oct 20 '22 03:10

saw303


People also ask

How do I create a method in Groovy?

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.

How do you call a method in Groovy class?

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.

What is class and method in 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.

Can I use Java classes in Groovy?

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.


1 Answers

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.

  • First of all, you will need a 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).
  • Next you will need to call 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.
  • To follow the Groovy conventions you need to create a Closure subclass (maybe anonymous) with a doCall method of the Signature you want your method be. The String for registerInstanceMethod will be the name of the method
  • You can of course also leverage one of the existing MetaMethod subclasses (or your own one) to get there.
like image 52
blackdrag Avatar answered Oct 29 '22 19:10

blackdrag