Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Added open issues

...

Code Block
class A {
    // Code common to all properties
    final static Set PROPERTIES = new LinkedHashSet ()
    void invokeListener (String property, event) {
        ...
    }

    // Code generated per property
    final static String PROPERTY_X = 'x'
    static {
    	PROPERTIES.add (PROPERTY_X)
    }
    List listeners
    int x

    void addXListener (listener) {
        ...
    }
    boolean removeXListener (listener) {
        ...
    }
    void setX (int x) {
    	if (x != this.x) {
    	    int oldValue = this.x
    	    this.x = x
    	    invokeListener (PROPERTY_X, new PropertyChangeEvent (oldValue, x))
    	}
    }
}//
Note

This

example

needs

to

be

re-worked

to

conform

to

the

JavaBeans

specification

regarding

BoundProperties 

BoundProperties

specifically:

  • 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)

...

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
@Entity
class Foo
{
    @Id
    @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, Foo.SQL.name]
def cond = Sql.WHERE () { Foo.SQL.id >= 5 && Foo.SQL.name != 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 ()
   o.id = it[0]
   o.name = 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)

It seems that it is possible to write annotations into Java 1.4 classfiles (see Commons Attributes). But the questions is: Is this futile? There are only a few tools which support annotations and Java 1.4.

In this light, it makes more sense to add a switch to allow Groovy to write Java 5 classfiles, so users stuck to 1.4 can still use it and Java 5 users can upgrade when they want to.

Expand or Pass On

The compiler needs a way to decide what to do with an official Java 5 annotation like javax.persistence.Entity which is defined in EJB3: Expand it as a macro or pass it on into the class file so a third party library/tool can process it later.

Here, the user might want to decide differently per class (i.e. handle most of these cases with Hibernate and some corner cases with her own AST macro).

For Groovy-specific macros, the solution is to add a marker interface to the macro annotation.

Options

  • Add a config file to the compiler
  • Users have to use a different annotation which implements both Groovy's marker interface and javax.persistence.Entity

Links