Не удается динамически изменять или добавлять методы в классе, используя GroovyClassLoader - PullRequest
0 голосов
/ 26 ноября 2010

Я пытаюсь динамически изменять и добавлять методы класса, определенного в скрипте 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

Любая идея приветствуется!
Franck

1 Ответ

0 голосов
/ 27 ноября 2010

new GroovyClassLoader не является загрузчиком классов Groovy текущего потока.
Он будет удален после завершения метода suite() вместе со своими собственными ассоциациями Class и MetaClass.

Однако это работает:

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