Objects, Groovy and boilerplate

Juan Miguel Garcia Lopez
4 min readNov 6, 2022

--

Photo by Joanna Kosinska on Unsplash

One of the reasons I like Groovy so much is that the compiler works for you and never gets in the way. You write less code, which is always a good thing. Less code means fewer opportunities to screw up.

With Java, there is a lot of boilerplate that has to be written. Constructors, setters, getters, hashcode, equals… Good IDEs like IntelliJ can generate these for you automatically, but you need to make sure the implementations are kept up-to-date if you add or remove fields. There has to be a better way.

For instance, you can use annotations, like the ones provided by Project Lombok. Lombok is definitely a great option, but it is not part of the language so it has to be imported explicitly. And not everyone is familiar with this library. It would be better if we could rely on something that was part of the language implementation.

Enter Groovy, which offers all these features, and more, as part of the standard Groovy distribution. Internally, it uses a concept called Compile-time Metaprogramming, but we are not interested at this point in how it is done. We just want it to work because writing all that stuff manually is tedious.

Implementing ToString

Let’s start with an easy one. Writing toString manually is a royal pain in the ass, so let Groovy do this for you.

Just a simple annotation will do. Let’s see the output that toString produces by default:

produces

com.juan.gists.Address(100, Fifth Avenue, New York City, com.juan.gists.State(New York), com.juan.gists.Country(0, US))

Not bad, but we can make it less verbose by removing the package names and clearer by adding the property names:

Address(streetAddress:100, Fifth Avenue, town:New York City, state:State(name:New York), country:Country(population:0, name:US))

Much better. There are many other options, of course.

Equals and hashcode

Implementing equals is very verbose and it is easy to make a mistake, but Groovy can do that for you by using the EqualsAndHashCode annotation.

Automatically generating constructors

Let’s try to create a new Address object. The usually helpful IntelliJ is a bit puzzled because there is only one constructor: the default one with no arguments:

Let’s add the TupleConstructor annotation:

The TupleConstructor annotation has automatically generated a few constructors for you, including some with default values:

TupleConstructors offers many options. It even allows you to add some code to the generated constructors.

Address(streetAddress:255 BOSTON AVENUE, town:null, state:null, country:null)

You will never have to manually write any constructor ever again!

Making a class immutable

The Immutable annotation can be used to create a class of immutable objects. Making a class immutable is not always possible, but it is desirable, as it makes the code easier to understand.

Remember the TupleConstructor example above that changed the street address to uppercase? You cannot do anymore if you use Immutable, as all the fields are final:

IntelliJ will also complain about state and country:

Building objects from a Map

With the MapConstructor annotation, you can pass a map to initialise a constructor. Groovy will try to find all entries in the map where the key matches one of the properties in the object, and will use the value to initialise that property.

Remember that, by default, Groovy allows you to use a map-style constructor call, but you need to pass a value to all the fields. With a MapConstructor annotation, you can be more selective.

Putting them all together: Canonical

The @Canonical meta-annotation is a combination of the @ToString, @EqualsAndHashCode and @TupleConstructor annotations. Even less boilerplate!

Bonus: using constructors Python style with Newify

You can even get rid of the calls to the “new” operator if you are that lazy. Note that the annotation has to be added to the code that creates the objects, rather than to the involved classes.

The Groovy compiler will automatically add the calls to “new” for you.

Conclusion

Groovy tries very hard to make your life easier and simple so that you can focus on building your application. Try to manually write all the code that the Canonical annotation generates automatically and you will see what I mean.

I am not done with this topic but will need to wait for another article. Until then!

--

--

Juan Miguel Garcia Lopez
Juan Miguel Garcia Lopez

No responses yet