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@mrhaki.com')
mrhaki.with {
assert name == 'mrhaki'
assert email == 'mrhaki@mrhaki.com'
}
// 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 == 'mrhaki@mrhaki.com'
}
// The properties are still immutable:
try {
hubert.email = 'new-mail@host.nl'
} catch (ReadOnlyPropertyException e) {
assert 'Cannot set readonly property: email for class: User' == e.message
}
Code written with Groovy 2.2.