Groovy 将代码添加到构造函数

Posted

技术标签:

【中文标题】Groovy 将代码添加到构造函数【英文标题】:Groovy adding code to a constructor 【发布时间】:2011-08-19 22:18:31 【问题描述】:

Groovy 中是否有一种方法可以在实例化类时向构造函数添加代码?我有一个 Groovy 类(但我不能修改这个特定类的源代码),但我希望有一种方法可以注入代码(可能通过元类),这样我的代码就会作为构造函数的一部分运行(在这个如果只有一个,默认构造函数)。

谢谢, 杰夫

【问题讨论】:

我自己从来没有这样做过,但这可能会有所帮助groovy.codehaus.org/ExpandoMetaClass+-+Constructors 【参考方案1】:

可以覆盖构造函数,但这有点棘手,尤其是在覆盖默认构造函数时。您需要为类的metaClass.constructor 分配一个闭包,并且该闭包应该返回一个新实例。棘手的部分是,如果您调用已覆盖的构造函数,您将进入递归循环并生成堆栈溢出。您需要另一种方法来获取类的实例,例如不同的构造函数。

对于测试,有时可以绕过此限制。通常,首先实例化一个对象,然后重写构造函数以返回现有实例就足够了。示例:

class MyObject 
    String something
    MyObject()  something = "initialized" 


testInstance = new MyObject()
testInstance.something = "overriden"
MyObject.metaClass.constructor =  -> testInstance 

aNewObject = new MyObject()
assert aNewObject.is(testInstance)
assert aNewObject.something == "overriden"

【讨论】:

我想我应该能够使用 2 个构造函数来完成我需要完成的事情。谢谢。【参考方案2】:

可以添加新的构造函数或替换旧的构造函数。如果您需要原始构造函数,则可以使用反射:

MyObject.metaClass.constructor =  -> // for the no-arg ctor
  // use reflection to get the original constructor
  def constructor = MyObject.class.getConstructor()
  // create the new instance
  def instance = constructor.newInstance()
  // ... do some further stuff with the instance ...
  println "Created $instance"
  instance

请注意,如果您的构造函数有参数,则必须更改此设置,例如:

// Note that the closure contains the signature of the constructor
MyObject.metaClass.constructor =  int year, String reason ->
  def constructor = MyObject.class.getConstructor(Integer.TYPE, String.class)
  def instance = constructor.newInstance(
    2014, "Boy, am I really answering a question three years old?")
  // ... do some further stuff with the instance ...
  println "Created $instance"
  instance

PS:请注意,当您要添加尚不存在的构造函数时,请改用<< 运算符:MyObject.metaClass.constructor << /* as above */

【讨论】:

【参考方案3】:

您可以通过使用标准 Java 反射存储原始构造函数来绕过建议的解决方案中的限制。例如,这是我在 spock 测试中初始化一个类(基本注入):

def setupSpec() 
    MockPlexusContainer mockPlexusContainer = new MockPlexusContainer()
    def oldConstructor = MY_CLASS.constructors[0]

    MY_CLASS.metaClass.constructor =  ->
        def mojo = oldConstructor.newInstance()
        mockPlexusContainer.initializeContext(mojo)
        return mojo
    

这只会被调用一次,但每次有人调用构造函数时,我都会得到一个不同的实例,从而避免清理值并确保线程安全。

【讨论】:

以上是关于Groovy 将代码添加到构造函数的主要内容,如果未能解决你的问题,请参考以下文章

GroovyGroovy 方法调用 ( Groovy 构造函数中为成员赋值 | Groovy 函数的参数传递与键值对参数 | 完整代码示例 )

重写构造函数中调用的方法时,Groovy metaClass 失败?

Groovy循环控制 ( Java 语法循环 | 默认的 IntRange 构造函数 | 可设置翻转属性的 IntRange 构造函数 | 可设置是否包含 to 的构造函数 | 0..9 简写 )(代

如何将多个构造函数添加到结构?

有一个将输入添加到数组的构造函数

groovy File() 构造函数中的 GStringImpl