Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3

GroovyBeans are JavaBeans but using a much simpler syntax.
Here's an example:

Code Block
java
java
class Customer {
    // properties
    Integer id
    String name
    Date dob

    // sample code
    static void main(args) {
        def customer = new Customer(id:1, name:"Gromit", dob:new Date())
        println("Hello ${customer.name}")
    }
}
Code Block
Hello Gromit

Notice how the properties look just like public fields. You can also set named properties in a bean constructor in Groovy. In Groovy, fields and properties have been merged so that they act and look the same. So, the Groovy code above is equivalent to the following Java code:

Code Block
java
java
import java.util.Date;

public class Customer {
    // properties
    private Integer id;
    private String name;
    private Date dob;

    public Integer getId() {
        return this.id;
    }

    public String getName() {
        return this.name;
    }

    public Date getDob() {
        return this.dob;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setDob(Date dob) {
        this.dob = dob;
    }

    // sample code
    public static void main(String[] args) {
        Customer customer = new Customer();
        customer.setId(1);
        customer.setName("Gromit");
        customer.setDob(new Date());

        System.out.println("Hello " + customer.getName());
    }
}

Property and field rules

When Groovy is compiled to bytecode, the following rules are used.

  • If the name is declared with an access modifier (public, private or protected) then a field is generated.
  • A name declared with no access modifier generates a private field with public getter and setter (i.e. a property).
  • If a property is declared final the private field is created final and no setter is generated.
  • You can declare a property and also declare your own getter or setter.
  • You can declare a property and a field of the same name, the property will use that field then.
  • If you want a private or protected property you have to provide your own getter and setter which must be declared private or protected.
  • If you access a property from within the class the property is defined in at compile time with implicit or explicit this (for example this.foo, or simply foo), Groovy will access the field directly instead of going though the getter and setter.
  • If you access a property that does not exist using the explicit or implicit foo, then Groovy will access the property through the meta class, which may fail at runtime.

So, for example, you could create a read only property or a public read-only property with a protected setter like this:

Code Block
java
java
class Foo {
    // read only property
    final String name = "John"

    // read only property with public getter and protected setter
    Integer amount
    protected void setAmount(Integer amount) { this.amount = amount }

    // dynamically typed property
    def cheese
}

Note that properties need some kind of identifier: e.g. a variable type ("String") or untyped using the "def" keyword.

Why a field with public access modifier do not have getter and setter generated? If we'd generate getter / setter all the time, it means Groovy would not let you not define getters / setters, which can be problematic when you really don't want to geters / setters to be exposed.

Closures and listeners

Though Groovy doesn't support anonymous inner classes, it is possible to define action listeners inline through the means of closures. So instead of writing in Java:

Code Block
java
java
Processor deviceProc = ...
deviceProc.addControllerListener(new ControllerListener() {
   public void controllerUpdate(ControllerEvent ce) {
      ...
   }
}

You can do that in Groovy with a closure:

Code Block
// Add a closure for a particular method on the listener interface
deviceProc.controllerUpdate = { ce -> println "I was just called with event $ce" }

Notice how the closure is for a method on the listener interface (controllerUpdate), and not for the interface itself(ControllerListener).  This technique means that Groovy's listener closures are used like a ListenerAdapter where only one method of interest is overridden.  Beware: mistakenly misspelling the method name to override or using the interface name instead can be tricky to catch, because Groovy's parser may see this as a property assignment rather than a closure for an event listener.

This mechanism is heavily used in the Swing builder to define event listeners for various components and listeners. The JavaBeans introspector is used to make event listener methods available as properties which can be set with a closure.

The Java Beans introspector (java.beans.Introspector) which will look for a BeanInfo for your bean or create one using its own naming conventions. (See the Java Beans spec for details of the naming conventions it uses if you don't provide your own BeanInfo class). We're not performing any naming conventions ourselves - the standard Java Bean introspector does that for us.

Basically the BeanInfo is retrieved for a bean and its EventSetDescriptors are exposed as properties (assuming there is no clash with regular beans). It's actually the EventSetDescriptor.getListenerMethods() which is exposed as a writable property which can be assigned to a closure.