Uploaded image for project: 'Groovy'
  1. Groovy
  2. GROOVY-3606

@Bindable generates wrong byte code depending on compilation order

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Major
    • Resolution: Fixed
    • 1.6.3
    • 1.6.4, 1.7-beta-1
    • Swing
    • None
    • Patch

    Description

      BindableASTTransformation checks if PropertyChangeSupport needs to be injected into the target class or not. A recent fix takes into account if the user defined some particular methods on the class, or if those methods are defined in the class hierarchy. But that check fails if the child class is compiled ahead of the super class. To wit, with the following sample classes

      import groovy.beans.Bindable
      import java.beans.PropertyChangeListener
      import java.beans.PropertyChangeEvent
      
      class Foo implements PropertyChangeListener {
        @Bindable String name
      
        Foo() {
          addPropertyChangeListener(this)
        }
      
        void propertyChange(PropertyChangeEvent e) {}
      }
      
      import groovy.beans.Bindable
      
      class Bar extends Foo {
        @Bindable int id
      
        Bar() {
          super()
        }
      }
      

      when Foo is compiled before Bar everything works just nicely, this is the generated byte code

      [aalmiray@aalmiray-pc:/tmp]$ groovyc Foo.groovy Bar.groovy
      [aalmiray@aalmiray-pc:/tmp]$ javap Foo
      Compiled from "Foo.groovy"
      public class Foo extends java.lang.Object implements java.beans.PropertyChangeListener,groovy.lang.GroovyObject{
          public static final java.lang.Class $ownClass;
          public static java.lang.Long __timeStamp;
          public static java.lang.Long __timeStamp__239_neverHappen1246557680149;
          public Foo();
          public void propertyChange(java.beans.PropertyChangeEvent);
          public void addPropertyChangeListener(java.beans.PropertyChangeListener);
          public void addPropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener);
          public void removePropertyChangeListener(java.beans.PropertyChangeListener);
          public void removePropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener);
          public void firePropertyChange(java.lang.String, java.lang.Object, java.lang.Object);
          public java.beans.PropertyChangeListener[] getPropertyChangeListeners();
          public void setName(java.lang.String);
          protected groovy.lang.MetaClass $getStaticMetaClass();
          public groovy.lang.MetaClass getMetaClass();
          public void setMetaClass(groovy.lang.MetaClass);
          public java.lang.Object invokeMethod(java.lang.String, java.lang.Object);
          public java.lang.Object getProperty(java.lang.String);
          public void setProperty(java.lang.String, java.lang.Object);
          static {};
          public java.lang.String getName();
          public void super$1$wait();
          public java.lang.String super$1$toString();
          public void super$1$wait(long);
          public void super$1$wait(long, int);
          public void super$1$notify();
          public void super$1$notifyAll();
          public java.lang.Class super$1$getClass();
          public boolean super$1$equals(java.lang.Object);
          public java.lang.Object super$1$clone();
          public int super$1$hashCode();
          public void super$1$finalize();
          static java.lang.Class class$(java.lang.String);
      }
      
      [aalmiray@aalmiray-pc:/tmp]$ javap Bar
      Compiled from "Bar.groovy"
      public class Bar extends Foo{
          public static final java.lang.Class $ownClass;
          public static java.lang.Long __timeStamp;
          public static java.lang.Long __timeStamp__239_neverHappen1246557680247;
          public Bar();
          public void setId(int);
          protected groovy.lang.MetaClass $getStaticMetaClass();
          static {};
          public int getId();
          public java.lang.Object super$2$getProperty(java.lang.String);
          public java.lang.String super$2$getName();
          public java.lang.String super$1$toString();
          public void super$2$setProperty(java.lang.String, java.lang.Object);
          public void super$1$notify();
          public void super$2$propertyChange(java.beans.PropertyChangeEvent);
          public void super$2$removePropertyChangeListener(java.beans.PropertyChangeListener);
          public void super$1$notifyAll();
          public void super$2$removePropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener);
          public void super$2$firePropertyChange(java.lang.String, java.lang.Object, java.lang.Object);
          public void super$2$addPropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener);
          public void super$1$wait();
          public groovy.lang.MetaClass super$2$getMetaClass();
          public void super$2$addPropertyChangeListener(java.beans.PropertyChangeListener);
          public void super$1$wait(long, int);
          public void super$2$setMetaClass(groovy.lang.MetaClass);
          public void super$2$setName(java.lang.String);
          public groovy.lang.MetaClass super$2$$getStaticMetaClass();
          public java.beans.PropertyChangeListener[] super$2$getPropertyChangeListeners();
          public java.lang.Object super$2$invokeMethod(java.lang.String, java.lang.Object);
          static java.lang.Class class$(java.lang.String);
      }
      

      Now look what happens if Bar is compiled ahead of Foo

      [aalmiray@aalmiray-pc:/tmp]$ rm -f *class
      [aalmiray@aalmiray-pc:/tmp]$ groovyc Bar.groovy Foo.groovy
      [aalmiray@aalmiray-pc:/tmp]$ javap Foo
      Compiled from "Foo.groovy"
      public class Foo extends java.lang.Object implements java.beans.PropertyChangeListener,groovy.lang.GroovyObject{
          public static final java.lang.Class $ownClass;
          public static java.lang.Long __timeStamp;
          public static java.lang.Long __timeStamp__239_neverHappen1246557703276;
          public Foo();
          public void propertyChange(java.beans.PropertyChangeEvent);
          public void addPropertyChangeListener(java.beans.PropertyChangeListener);
          public void addPropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener);
          public void removePropertyChangeListener(java.beans.PropertyChangeListener);
          public void removePropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener);
          public void firePropertyChange(java.lang.String, java.lang.Object, java.lang.Object);
          public java.beans.PropertyChangeListener[] getPropertyChangeListeners();
          public void setName(java.lang.String);
          protected groovy.lang.MetaClass $getStaticMetaClass();
          public groovy.lang.MetaClass getMetaClass();
          public void setMetaClass(groovy.lang.MetaClass);
          public java.lang.Object invokeMethod(java.lang.String, java.lang.Object);
          public java.lang.Object getProperty(java.lang.String);
          public void setProperty(java.lang.String, java.lang.Object);
          static {};
          public java.lang.String getName();
          public void super$1$wait();
          public java.lang.String super$1$toString();
          public void super$1$wait(long);
          public void super$1$wait(long, int);
          public void super$1$notify();
          public void super$1$notifyAll();
          public java.lang.Class super$1$getClass();
          public boolean super$1$equals(java.lang.Object);
          public java.lang.Object super$1$clone();
          public int super$1$hashCode();
          public void super$1$finalize();
          static java.lang.Class class$(java.lang.String);
      }
      
      [aalmiray@aalmiray-pc:/tmp]$ javap Bar
      Compiled from "Bar.groovy"
      public class Bar extends Foo{
          public static final java.lang.Class $ownClass;
          public static java.lang.Long __timeStamp;
          public static java.lang.Long __timeStamp__239_neverHappen1246557703363;
          public Bar();
          // THE FOLLOWING 6 METHODS SHOULD NOT HAVE BEN INJECTED HERE!
          public void addPropertyChangeListener(java.beans.PropertyChangeListener);
          public void addPropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener);
          public void removePropertyChangeListener(java.beans.PropertyChangeListener);
          public void removePropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener);
          public void firePropertyChange(java.lang.String, java.lang.Object, java.lang.Object);
          public java.beans.PropertyChangeListener[] getPropertyChangeListeners();
          //
          public void setId(int);
          protected groovy.lang.MetaClass $getStaticMetaClass();
          static {};
          public int getId();
          public java.lang.Object super$2$getProperty(java.lang.String);
          public java.lang.String super$2$getName();
          public java.lang.String super$1$toString();
          public void super$2$setProperty(java.lang.String, java.lang.Object);
          public void super$1$notify();
          public void super$2$propertyChange(java.beans.PropertyChangeEvent);
          public void super$2$removePropertyChangeListener(java.beans.PropertyChangeListener);
          public void super$1$notifyAll();
          public void super$2$removePropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener);
          public void super$2$firePropertyChange(java.lang.String, java.lang.Object, java.lang.Object);
          public void super$2$addPropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener);
          public void super$1$wait();
          public groovy.lang.MetaClass super$2$getMetaClass();
          public void super$2$addPropertyChangeListener(java.beans.PropertyChangeListener);
          public void super$1$wait(long, int);
          public void super$2$setMetaClass(groovy.lang.MetaClass);
          public void super$2$setName(java.lang.String);
          public groovy.lang.MetaClass super$2$$getStaticMetaClass();
          public java.beans.PropertyChangeListener[] super$2$getPropertyChangeListeners();
          public java.lang.Object super$2$invokeMethod(java.lang.String, java.lang.Object);
          static java.lang.Class class$(java.lang.String);
      }
      

      Attachments

        1. groovy-3606.patch
          5 kB
          Andres Almiray

        Activity

          People

            shemnon Daniel Ferrin
            aalmiray Andres Almiray
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: