Groovy AST transformations, such as @ValueObject and @NonNull, which makes constructing an instance more bullet-proof.
Groovy has the Immutable
annotation which allows to create immutable classes, which is a prerequisite for creating value objects. Unfortunately, when a class has been annotated with Immutable
it's no longer possible to add your own constructor to verify if provided parameters are not null
, making our value objects really bullet-proof.
See Ted Vinke Blog: Make Your Groovy Objects More Bullet-Proof
Bulletproof helps to fill this gap by adding a few AST transformations.
- The
NonNull
annotation which modifies every constructor to perform null-checks. Add this to anImmutable
class and nonull
slips past your constructor. - The
ValueObject
meta-annotation which puts bothNonNull
andImmutable
on your class as a convenience to do above step with one annotation.
Bulletproof requires Java 7 or later.
Add the bulletproof jar to the classpath in your preferred way and you're set.
@Grab('com.github.tvinke:bulletproof:0.2')
compile group: 'com.github.tvinke', name: 'bulletproof', version: '0.2'
<dependency>
<groupId>com.github.tvinke</groupId>
<artifactId>bulletproof</artifactId>
<version>0.2</version>
</dependency>
Consult the bulletproof 0.2 Groovydocs for complete API information.
The NonNull
annotation on the class-level triggers an AST transformation which modifies every constructor to perform a null-check.
@groovy.transform.Immutable
@tvinke.bulletproof.transform.NonNull
class Person {
String name
}
new Person() // throws IllegalArgumentException: "Name can not be null"
The ValueObject
meta-annotation combines the Immutable
and NonNull
annotations, which is used to assist in the creation of value objects.
@tvinke.bulletproof.transform.ValueObject
class Money {
BigDecimal amount
}
new Money(amount: null) // throws IllegalArgumentException because of NonNull
def money = new Money(2.95)
money.amount = 3.0 // throws ReadOnlyPropertyException because of Immutable
- Consider allowing a mutable object (e.g. default Map constructor, or with
TupleConstructor
) also to have null-checks performed. In this case probably also through the setters. - In above case, then probably you need you want to specify which properties need to be null-checked instead of just everything.