Registration of meta classes for multiple classes in class hierarchy

View: New views
2 Messages — Rating Filter:   Alert me  

Registration of meta classes for multiple classes in class hierarchy

by Fabian Knittel :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi,

I'm trying to save/restore meta classes during unit testing, so that
changes to the meta classes stay contained within the tests. (Grails'
GrailsUnitTestCase.mockDomain and friends do very similar stuff.)

Everything works fine as long as I don't work with child and parent
classes simultaneously.  I've reduced the unexpected behaviour to the
following groovy script (for GroovyConsole):

  class EmptyClass {}
  class EmptyChildClass extends EmptyClass {}

  void blankMetaClass(Class cls) {
      def mc = new ExpandoMetaClass(cls, true, true)
      mc.initialize()
      GroovySystem.metaClassRegistry.setMetaClass(cls, mc)
  }

  void testMeta() {
      def el = new EmptyChildClass()

      blankMetaClass(EmptyChildClass)
      blankMetaClass(EmptyClass)

      EmptyClass.metaClass.foo = {-> "parent"}
      EmptyChildClass.metaClass.foo = {-> "child"}

      assert "child" == el.foo()  // <-- The assertion fails!
  }

  ExpandoMetaClass.enableGlobally()
  testMeta()

(Note: This has no "meta class restore" functionality, but uses a few
building blocks which revealed the problems.)

Although "el" is an instance of EmptyChildClass, the closure assigned to
EmptyClass' meta class is called.  This does not happen, if the
EmptyChildClass is instantiated _after_ replacing the meta classes.
I.e., the following change results in the expected behaviour:

   void testMeta() {
 -     def el = new EmptyChildClass()
       replaceMetaClass(EmptyChildClass)
       replaceMetaClass(EmptyClass)

 +     def el = new EmptyChildClass()

       EmptyClass.metaClass.foo = {-> "parent"}
       EmptyChildClass.metaClass.foo = {-> "child"}

       assert "child" == el.foo()  // The assertion fails.
   }

Alternatively, leaving out the call to
GroovySystem.metaClassRegistry.setMetaClass() fixes things too. Neither
work-around is optimal for my use-case (with some refactoring, I could
probably use the former), but either way I'd really like to be able to
understand what's going on.

Can anyone enlighten me? What am I doing wrong? Or is this maybe a bug
in groovy? (I've tested the above with groovy 1.6.3 (mainly because it's
bundled with grails 1.1.1), maybe I should try a newer version?)

Thanks in advance for any pointers ...
Fabian

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email



Re: Registration of meta classes for multiple classes in class hierarchy

by Fabian Knittel :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi again,

Fabian Knittel wrote:
> [...] Or is this maybe a bug
> in groovy? (I've tested the above with groovy 1.6.3 (mainly because it's
> bundled with grails 1.1.1), maybe I should try a newer version?)

I came around to testing my script with Groovy 1.6.5 and the
(unexpected) behaviour remains the same, so upgrading won't help me.

Fabian

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email