Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Groovy Goodness: Implicit Closure Coercion

DZone's Guide to

Groovy Goodness: Implicit Closure Coercion

· Java Zone
Free Resource

Get the Edge with a Professional Java IDE. 30-day free trial.

Groovy is awesome and closures are cool. In Java 8 we will see lambdas which are similar like closures. A Java lambda will be automatically converted to an interface type if the interface contains only one single abstract method (SAM). In Groovy we can convert a closure into an interface type by using the as keyword. But since Groovy 2.2 we don't have to use the as keyword, but let Groovy, like Java lambdas, convert a closure implicitly to an interface type. This works for interfaces with a single method, but Groovy wouldn't be Groovy if it didn't work for abstract classes with one abstract method. So, yes, it also works for abstract classes with a single abstract method.

In the following code we define a new class User and make the class send out PropertyChangeEvent events when a property value changes by applying the @Bindable AST transformation to the class. The @Bindable annotation will make sure all code is generated in the class file to inform classes implementing the PropertyChangeListener interface of changes in property values. The nice thing about thePropertyChangeListener interface is that is contains a single method and applies to Single Abstract Method (SAM). In the sample we use a closure that is automatically converted to a PropertyChangeListener type.

import groovy.beans.*
import java.beans.*

@Bindable
class User {
    String name, email
}

def u = new User(name: 'mrhaki', email: 'mrhaki@mrhaki.com')

// Since Groovy 2.2 we don't have to use the as keyword like
// { ... } as PropertyChangeListener,
// but we can rely on implicit coercion.
u.addPropertyChangeListener { event ->
    println "Changed property $event.propertyName from $event.oldValue to $event.newValue"
}

u.name = 'Hubert A. Klein Ikkink'
// Output: Changed property name from mrhaki to Hubert A. Klein Ikkink

u.email = 'hubert@mrhaki.com'
// Output: Changed property email from mrhaki@mrhaki.com to hubert@mrhaki.com

In the next sample we define an abstract class ChangedProperty with a single abstract method (SAM) as listener implementation. When we define an instance we can use a closure and it will automatically be the implementation of the abstract method:

import groovy.beans.*
import java.beans.*

@Bindable
class User {
    String name, email
}

def u = new User(name: 'mrhaki', email: 'mrhaki@mrhaki.com')

// Assign closure as implementation of single abstract method onPropertyChange
// in abstract class ChangedProperty.
ChangedProperty changedProperty = { event -> 
    println "Changed property $event.propertyName from $event.oldValue to $event.newValue" 
}
u.addPropertyChangeListener changedProperty

u.name = 'Hubert A. Klein Ikkink'
// Output: Changed property name from mrhaki to Hubert A. Klein Ikkink

u.email = 'hubert@mrhaki.com'
// Output: Changed property email from mrhaki@mrhaki.com to hubert@mrhaki.com

assert changedProperty.events.size() == 2
assert changedProperty.events.first().oldValue == 'mrhaki'
assert changedProperty.events.first().newValue == 'Hubert A. Klein Ikkink'

abstract class ChangedProperty implements PropertyChangeListener {

    List<PropertyChangeEvent> events = []

    void propertyChange(PropertyChangeEvent event) {
        events << event
        onPropertyChange(event);
    }
    
    abstract void onPropertyChange(PropertyChangeEvent event)

}

Code written with Groovy 2.2.

Get the Java IDE that understands code & makes developing enjoyable. Level up your code with IntelliJ IDEA. Download the free trial.

Topics:

Published at DZone with permission of Hubert Klein Ikkink, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}