【问题标题】:Cannot dynamically change or add methods in a class using GroovyClassLoader无法使用 GroovyClassLoader 在类中动态更改或添加方法
【发布时间】:2011-05-16 08:31:17
【问题描述】:

我尝试从另一个 groovy 脚本动态更改和添加在 groovy 脚本中定义的类的方法,但如果我直接在 .metaClass 中使用类名,我无法弄清楚为什么它会起作用。但如果我使用 GroovyClassLoader 加载类(我需要这样做!)。

在一个文件“MyTest.groovy”中我有

class MyTest {

   public void setUp() {
      println "SET UP"
   }
   public void tearDown() {
      println "TEAR DOWN"
   }
   public void testA() {
      println "testA"
   }
}

另一个文件“suite.groovy”包含

#!/usr/bin/env groovy

public class MyTestSuite {
   // For debug
   public static printClassLoader(Class cls) {
      ClassLoader loader = cls.classLoader
      while (loader) {
         println loader.class
         println loader.URLs.join("\n")
         println "\n\n"
         loader = loader.parent
      }
   }

   public static void suite()  {
      // First method to define my class (change/addition of methods works)
      //Class testClass = MyTest

      // Second way to define my class (change/addition of methods doesn't work)
      ClassLoader parent = MyTestSuite.class.getClassLoader();
      GroovyClassLoader gcl = new GroovyClassLoader(parent);
      Class testClass = gcl.parseClass(new File("MyTest.groovy"));

      printClassLoader(testClass)

      testClass.metaClass.setUp = {-> println "I'm your new setUp()" ;}
      testClass.metaClass.newTest = {-> println "I'm your new newTest()" ; }
   }
}

MyTestSuite.suite()
MyTest aTest = new MyTest()
aTest.setUp()
aTest.newTest()

使用第一种方法,我得到了预期的结果:

I'm your new setUp()
I'm your new newTest()

但是第二个我得到了

SET UP
Caught: groovy.lang.MissingMethodException: No signature of method: MyTest.newTest() is applicable for argument types: () values: []
Possible solutions: testA(), getAt(java.lang.String), wait(), inspect(), every()
    at suite.run(suite.groovy:34)

有趣地修改现有方法不起作用,但没有例外,但尝试添加新方法会抛出一个。 我认为它必须对使用的类加载器做一些事情,但无法弄清楚究竟是什么以及要改变什么! 对于第一个版本,这里是类加载器:

class groovy.lang.GroovyClassLoader$InnerLoader
class groovy.lang.GroovyClassLoader
class org.codehaus.groovy.tools.RootLoader
class sun.misc.Launcher$AppClassLoader
class sun.misc.Launcher$ExtClassLoader

对于第二个版本:

class groovy.lang.GroovyClassLoader$InnerLoader
class groovy.lang.GroovyClassLoader
class groovy.lang.GroovyClassLoader$InnerLoader
class groovy.lang.GroovyClassLoader
class org.codehaus.groovy.tools.RootLoader
class sun.misc.Launcher$AppClassLoader
class sun.misc.Launcher$ExtClassLoader

欢迎任何想法!
弗兰克

【问题讨论】:

    标签: groovy dynamic metaclass groovyclassloader


    【解决方案1】:

    new GroovyClassLoader 不是当前线程的 Groovy 类加载器。
    它将在 suite() 方法完成后处理 - 连同它自己的 ClassMetaClass 关联。

    但是,这是可行的:

    Class testClass = gcl.parseClass(new File("MyTest.groovy"));
    testClass = Class.forName(testClass.getName())
    

    【讨论】:

    • 您好 Robbert,感谢您的洞察力。我不确定新的 Groovy 类加载器是否会被释放,因为它有对父级的引用。无论如何,您的解决方案不起作用(捕获:java.lang.ClassNotFoundException:MyTest)。我试图弄清楚不同的类加载器是如何链接的,但不幸的是,关于这一点的 groovy 文档不清楚且不完整:groovy.codehaus.org/Groovy+Internals。所以我想我会尝试在我的代码中使用第一个选项。
    • 当没有 other 对象引用它时,将释放一个对象(反之亦然)。 - 至于错误,请尝试使用完全合格的路径作为开始。 - 我已经测试了代码:它确实有效。
    猜你喜欢
    • 1970-01-01
    • 2011-11-15
    • 1970-01-01
    • 1970-01-01
    • 2016-05-01
    • 2010-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多