Versions Compared


  • This line was added.
  • This line was removed.
  • Formatting was changed.


Code Block
class A {
    @BoundProperty     int x

should become

Code Block
import javax.beans.*;

class A {
    // Codethe commonfollowing tois alladded propertiesonly once per class
 final static Set PROPERTIESPropertyChangeSupport =propertyChangeSupport
LinkedHashSet ()     void invokeListener addPropertyChangeListener(String property, eventPropertyChangeListner listner) {

    // Code generated per property
void addPropertyChangeListener(String property, PropertyChangeListner listner) {
   final static String PROPERTY_X = 'x'
 propertyChangeSupport.addPropertyChangeListner(property, listener)
   static {}

 void removePropertyChangeListener(PropertyChangeListner listner) {
   }     List listenerspropertyChangeSupport.removePropertyChangeListner(listener)
x    void removePropertyChangeListener(String voidproperty, addXListenerPropertyChangeListner (listenerlistner) {
propertyChangeSupport.removePropertyChangeListner(property, listener)

   boolean removeXListenerPropertyChangeSupport[] getPropertyChangeListeners(listener) {
        return propertyChangeSupport...getPropertyChangeListeners

   void setX// (intthe x)following {is added per each annotated 	ifproeprty
(x != this.x) { private int x

	    intvoid oldValuesetX =(int this.x) {
    	propertyChangeSupport.firePropertyChanged('x', this.x,   this.x = x)

  invokeListener (PROPERTY_X, new PropertyChangeEvent (oldValue, x)) int getX() {
       	} return x;

This example needs to be re-worked to conform to the JavaBeans specification regarding BoundProperties


  • When using code completion, the additional fields and methods should be visible.
  • The added code should be lean and fast
  • It should not get in the way of existing user code, for example, it should be possible to define a custom setter which gets wrapped by the code above
  • If a custom setter exists, it should be possible to invoke it before the comparison (so you can define setters which convert the value before assigning it)

This leads to a couple of demands which an AST Macro Processor (AMP) must met:


SQL enhanced code is pretty similar to bound properties but more code is generated. The first step is to define the class which maps a database table to a Java object:

Code Block
class Foo
    @Column (type:java.sql.Types.INTEGER)
    int id
    @Column (type:java.sql.Types.CHAR, size:20)
    String name

After this is compiled, I want to see a special field "SQL" which I can use to build database queries like so:

Code Block
def columns = [Foo.SQL.value,]
def cond = Sql.WHERE () { >= 5 && != null }
def list = Sql.SELECT (columns, table:Foo.SQL.TABLE, where:cond, class:Foo.class)

This gets converted by the compiler into:

Code Block
def list = []
def _sql = "SELECT id, name FROM foo WHERE id >= ? AND name IS NOT NULL"
_sql = Sql.eachRow (_sql, [5]) {
   Foo o = new Foo () = it[0] = it[1]
   list << o

The SQL object in Foo also gives access to the standard DAO methods like loading an object by its primary key:

Code Block
def foo = Foo.SQL.load (5)

In addition to the simple bound property example, the AMP must also be able to note the usage of an annotated object, so it can convert the Groovy code into SQL at compile time (and possibly check it for mistakes).

Open Issues

Java 1.4/5

Groovy 1.x must run on Java 1.4. We must decide what to do with non-macro annotations, whether we want to support a switch to generate Java 5 classfiles (so Groovy can generate code for third party APTs like Hibernate)