【问题标题】:Cloning and extending class in GroovyGroovy 中的克隆和扩展类
【发布时间】:2018-06-21 17:54:52
【问题描述】:

我正在尝试在 Groovy 中动态生成类。我的做法是这样的:

class MetaClassTest {

    static class TestClass {

        String getName() {
            return "Jake"
        }
    }

    public static void main(String[] args) {
        def testClass = TestClass
        def metaMethod = testClass.metaClass.getMetaMethod('getName', [] as Class[])
        testClass.metaClass.getName = {
            metaMethod.invoke(delegate) + " and the Fatman"
        }
        assert testClass.newInstance().name == "Jake and the Fatman"
    }
}

然而,这改变了我不想要的原始类的行为。所以我的问题是:

如何动态克隆(并且可能重命名)现有类,以便能够创建多个派生类?

【问题讨论】:

  • 所以也许这应该是通常的extendsclass MyTestClass extends TestClass...
  • 或使用@Delegate:class MyTextClass{ @Delegate TestClass delegate; }
  • 这不是动态代码(如果没有在运行时通过GroovyClassLoader 进行评估,这也是一个选项,但不是很好)。
  • 也许你应该扩展你的问题?因为您的代码示例也不是真正动态的......究竟应该是动态的?
  • 动态生成类 - 最简单的方法是使用extends@Delegate 生成真实的类代码并将其解析/加载到类加载器中。

标签: java groovy reflection metaprogramming metaclass


【解决方案1】:

您可以覆盖类实例方法:

import groovy.transform.AutoClone

@AutoClone
class TestClass {
   String getName() {
      return "Jake"
   }
}

def tc1 = new TestClass()
def tc2 = tc1.clone()
tc1.metaClass.getName = {'Fatman'}
tc2.metaClass.getName = {'Joe'}
assert tc1.getName() == 'Fatman'
assert tc2.getName() == 'Joe'
assert new TestClass().getName() == 'Jake'

【讨论】:

  • 我知道,但这不是我想要的。
【解决方案2】:

我不确定以下是否有效,但可能值得一试:您能否检查是否可以以某种方式深度复制 TestClass,然后修改唯一的克隆类?以下可能会派上用场:

使用autoclone

也许groovy lang metaprogramming 可以寻找更多关于元编程的信息。

【讨论】:

    【解决方案3】:

    到目前为止,最透明(即使仍然很脏)的解决方案已经在这里暗示了。我可以使用GroovyClassLoader.parse() 方法创建子类骨架,然后通过metaClass 丰富它。

    class TestClass {
    
        String getName() {
            return "Jake"
        }
    }
    
    def parentClass = TestClass
    def groovyClassLoader = new GroovyClassLoader(parentClass.classLoader)
    
    def childClass1 = groovyClassLoader.parseClass("class ChildClass1 extends ${ parentClass.canonicalName } {}")
    def oldGetName1 = childClass1.metaClass.getMetaMethod('getName', [] as Class[])
    childClass1.metaClass.getName = {
        oldGetName1.invoke(delegate) + " and the Fatman"
    }
    
    def childClass2 = groovyClassLoader.parseClass("class ChildClass2 extends ${ parentClass.canonicalName } {}")
    def oldGetName2 = childClass2.metaClass.getMetaMethod('getName', [] as Class[])
    childClass2.metaClass.getName = {
        oldGetName2.invoke(delegate) + " the Dog"
    }
    
    assert childClass1.newInstance().name == "Jake and the Fatman"
    assert childClass2.newInstance().name == "Jake the Dog"
    

    我之所以在运行时动态创建类,是因为可以使用由几乎没有任何编程技能的人编写的 Groovy DSL 脚本来扩展应用程序。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-21
      • 1970-01-01
      • 2020-03-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多