【问题标题】:Adding methods to a class using Groovy in Java在 Java 中使用 Groovy 向类添加方法
【发布时间】:2015-11-27 19:44:33
【问题描述】:

我正在开发一个使用 Groovy 作为编译时依赖项的 Java 模块,我想在不编写 Groovy 代码的情况下向我的 Java 类 Person(如 Groovy JDK)添加一个方法。

在 Groovy 中我会这样实现

Person.meta.doSomething = { String param -> println "do something: ${param}" }

如何使用 Java 中的 Groovy API 来做到这一点?

编辑 1:

到目前为止,我已经实现了以下内容,而且我快到了。我为Person 实例化一个Expando 类并注册一个MethodClosure,它将方法调用委托给PersonDefaultMethods 类中的一个方法。

ExpandoMetaClass expando = new ExpandoMetaClass (Person.class, true, false);
expando.registerInstanceMethod ("format", new MethodClosure (new PersonDefaultMethods(), "format"));
expando.initialize ();

PersonDefaultMethods 包含我在 Expando 类中声明的方法的实现。

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();
    }
}

当我知道在此上下文中执行 Groovy 脚本时,我可以在 Person 实例上调用 format 方法,但我无法像通常使用闭包一样访问 delegate

编辑 2:

使用闭包子类或匿名闭包类的方法在我的实现中失败了。

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 ();

这可以完成工作。谢谢。

【问题讨论】:

  • 即使你可以让它工作,你的代码不是会变成一堆查找和注册表调用吗? Java 不适合这种实例扩展。因此 Groovy
  • 我完全同意你的看法。我尝试使用这种方法的唯一原因是我的公司使用 Eclipse(不支持 Groovy),如果我开始将 Groovy 类放入他们的工作区,项目将不再构建......我知道这很糟糕情况,但我不能改变它(还)。
  • re:“无法访问委托”。在 MethodClosure 中,委托/所有者用于方法调用,这里是 PersonDefaultMethods,所以它不会像这样工作。您将需要一个 Closure 子类。

标签: java groovy metaclass


【解决方案1】:

您可以通过GroovySystem.getMetaClassRegistry().getMetaClass(Person.class); 更好地获取当前的元类。但是要模拟上述情况,您需要手动执行 Groovy 在后台为您执行的几件事。

  • 首先,您需要一个ExpandoMetaClass(简称EMC)。如果上面的元类不是 EMC,您需要创建一个并在注册表中注册它:ExpandoMetaClass emc = new ExpandoMetaClass(Person.class)
  • 接下来,您需要使用 String 和 Closure 或 MetaMethod 调用 registerInstanceMethod。上面的变体是闭包版本,会在后台调用另一个变体。
  • 要遵循 Groovy 约定,您需要使用您想要的签名的 doCall 方法创建一个闭包子类(可能是匿名的)。 registerInstanceMethod 的字符串将是方法的名称
  • 您当然也可以利用现有的 MetaMethod 子类之一(或您自己的子类)来实现目标。

【讨论】:

  • 感谢您的解释。我应用了它,但现在遇到了异常(请参阅更新的问题)
猜你喜欢
  • 1970-01-01
  • 2010-12-09
  • 1970-01-01
  • 2017-12-27
  • 2016-02-27
  • 2016-06-06
  • 2010-11-30
  • 2013-11-15
  • 2013-03-06
相关资源
最近更新 更多