简体   繁体   中英

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM