We use JavaBeans a lot in our day to day Java programming. GroovyBeans use a much simpler syntax to get the same result. If we define a property in a JavaBean we must provide the corresponding get/set
methods. Most IDEs can generate these methods for us, but still the resulting code of a JavaBeans is less readable, because we have a lot of these methods.
Let's see some code first before we continue to look into GroovyBeans in more detail:
class Car { int numberOfDoors String model String brand boolean automatic double price String toString() { "[Car details => brand: '${brand}', model: '${model}', #doors: '${numberOfDoors}', automatic: '${automatic}', price: '${price}']" } }
We can use the Car
GroovyBean from a Groovy class or script:
Car ford = new Car(brand: 'Ford', model: 'Focus', numberOfDoors: 4, automatic: false, price: 24995) Car toyota = new Car(brand: 'Toyota', model: 'Verso') toyota.automatic = true // Yes, this invokes setAutomatic. toyota.setPrice(28919) // Normal set invocation. toyota.setNumberOfDoors 5 // In Groovy we can omit the parentheses. println ford // Output: [Car details => brand: 'Ford', model: 'Focus', #doors: '4', automatic: 'false', price: '24995.0'] println toyota // Output: [Car details => brand: 'Toyota', model: 'Verso', #doors: '5', automatic: 'true', price: '28919.0']
The class Car
is our GroovyBean. It looks like we defined only some fields, but because we haven't use any of the access modifiers (public, protected or private) these fields are actually properties when the code is compiled. Groovy will generate the get/set
methods so we can use the properties (see a complete list of rules the compiler uses to generate properties). To prove this is true we write a simple Java application to use the Car
class:
public class CarApp { public static void main(String[] args) { Car car = new Car(); car.setNumberOfDoors(3); car.setModel("A3"); car.setBrand("AUDI"); car.setPrice(32010); System.out.println(car); // Output: [Car details => brand: 'AUDI', model: 'A3', #doors: '3', automatic: 'false', price: '32010.0'] } }
GroovyBeans are flexible. To make a property read-only when designate a field final. Let's make the brand
final and run our Groovy script again. We now get the following exception:
Caught: groovy.lang.ReadOnlyPropertyException: Cannot set readonly property: brand for class: Car
We can add our own get/set
methods if we like. For example in the following code we have added our own protected set
method for the model
property:
class Car { int numberOfDoors String model final String brand // Readonly, public getter is generated, no setter. boolean automatic double price // Protected setter, public getter is still generated. protected void setModel(model) { this.model = modelName } String toString() { "[Car details => brand: '${brand}', model: '${model}', #doors: '${numberOfDoors}', automatic: '${automatic}', price: '${price}']" } }
To access the fields in GroovyBeans directly we can use the .@
operator. With this operator we bypass the get/set
methods. Of course we shouldn't be doing this, because that is why we have properties, but still the following code shows how it works:
class Car { int numberOfDoors String model String brand boolean automatic double price public void setBrand(brand) { this.brand = brand + ' (set via setter method)' } String toString() { "[Car details => brand: '${brand}', model: '${model}', #doors: '${numberOfDoors}', automatic: '${automatic}', price: '${price}']" } } Car ford = new Car(brand: 'Ford', model: 'Focus', numberOfDoors: 4, automatic: false, price: 24995) println ford.brand // Output: Ford (set via setter method) ford.@brand = 'Overrule brand' println ford.brand // Output: Overrule brand println ford.@brand // Output: Overrule brand
GroovyBeans provide a clean way to define beans with properties usable in Groovy and Java code.