Groovy 将代码添加到构造函数

发布于 2024-11-06 01:51:14 字数 146 浏览 1 评论 0原文

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

谢谢, 杰夫

Is there a way in Groovy that I can add code to a constructor when a class is instantiated? I have a Groovy class (but I can't modify the source of this particular one), but I was hoping there was a way to inject code (maybe via the metaclass) so my code gets run as part of the constructor (in this case there is only one, default constructor).

Thanks,
Jeff

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

请持续率性 2024-11-13 01:51:14

可以重写构造函数,但这有点棘手,特别是当您重写默认构造函数时。您需要为类的 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"

You can override the constructor, but it's a little tricky, particularly if you're overriding the default constructor. You need to assign a closure to the class's metaClass.constructor, and the closure should return a new instance. The tricky part is that if you call the constructor you've overriden, you'll get into a recursive loop and generate a stack overflow. You need another way to get an instance of the class, such as a different constructor.

For testing, it's sometimes possible to get around this limitation. Usually, it's enough to first instantiate an object, then override the constructor to return the existing instance. Example:

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"
和影子一齐双人舞 2024-11-13 01:51:14

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

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:请注意,当您要添加尚不存在的构造函数时,请使用 < code><< 运算符改为:MyObject.metaClass.constructor << { /* 如上 */ }

It is possible to add new constructors or replace the old one. If you need the original constructor, you can use reflection for that:

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 you have to change this if you have parameters to your constructors, e.g:

// 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: Note that when you want to add constructors which are not yet existent, use the << operator instead: MyObject.metaClass.constructor << { /* as above */ }.

野稚 2024-11-13 01:51:14

您可以通过使用标准 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
    }
}

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

You can bypass the limitations in the solution proposed by storing the original constructor using standard Java reflection. For example, this is what I do initialize a class (basic injection) in a spock test:

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
    }
}

This gets invoked only once, but eveytime someone calls a constructor I get a different instance avoiding cleaning values and ensuring thread safety.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文