Details
-
Bug
-
Status: Closed
-
Major
-
Resolution: Fixed
-
1.6.3
-
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); }