November 19, 2013

Groovy Goodness: Create CopyWith Method with Immutable Annotation

For a long time we can annotate a class with the @Immutable AST transformation so only an immutable instance of a class can be created. Since Groovy 2.2 we can use the annotation parameter copyWith. If we set the value of this parameter to true the AST transformation generates a new method copyWith() in the class. The method returns a new immutable instance of the class. We can pass a map with property names and values we want to set in the newly created instance.

In the following sample code we create a new immutable class User and we use the @Immutable annotation and set the parameter copyWith to true:

import groovy.transform.Immutable

@Immutable(copyWith = true)
class User {
    String name
    String email

// Create immutable instance of User.
def mrhaki = new User('mrhaki', '')

mrhaki.with {
    assert name == 'mrhaki'
    assert email == ''

// Use new copyWith method to create a new immutable
// instance of the User class where name property
// is changed and email property is unchanged.
def hubert = mrhaki.copyWith(name: 'Hubert A. Klein Ikkink')

hubert.with {
    assert name == 'Hubert A. Klein Ikkink'
    assert email == ''

// The properties are still immutable:
try { = ''
} catch (ReadOnlyPropertyException e) {
    assert 'Cannot set readonly property: email for class: User' == e.message

Code written with Groovy 2.2.