Comparing lombok features with groovy
Tags: groovy, java
Published: 2020-11-17 17:21:43

# Lombok

[Lombok](https://projectlombok.org/) is a java annotation processor which generates boilerplate code automatically in your classes at compile time. Many of lombok's feature overlap with features in the groovy language and [AST Transformations](https://groovy-lang.org/metaprogramming.html#_available_ast_transformations). Let us look at some of those features.

# val and var

**lombok**

[val](https://projectlombok.org/features/val) creates a type inferred, final local variable.

> the type will be inferred from the initializer expression. The local variable will also be made final.

[var](https://projectlombok.org/features/var) creates a type inferred, local variable.

> var works exactly like val, except the local variable is not marked as final.

**groovy**

Groovy has support for `def` and `var`. Since groovy is [optionally typed](https://groovy-lang.org/semantics.html#_optional_typing) these keywords do not normally provide type inference.

> def and var act as a type placeholder, i.e. a replacement for the type name, when you do not want to give an explicit type. (see [variable definition](https://groovy-lang.org/semantics.html#_variable_definition))

When using [`@TypeChecked`](https://docs.groovy-lang.org/latest/html/gapi/groovy/transform/TypeChecked.html) groovy will provide [type inference](https://groovy-lang.org/semantics.html#type-inference).

> When code is annotated with @TypeChecked, the compiler performs type inference. It doesn’t simply rely on static types, but also uses various techniques to infer the types of variables, return types, literals, …​ so that the code remains as clean as possible even if you activate the type checker.

To get the behavior of `val` in groovy apply `@TypeChecked` and declare a variable with `def` or `var` and the `final` keyword.

```
@TypeChecked
def final variable = '123'
```

# @NonNull

**lombok**

Lombok will generate null checks for any generate method which involves a field marked with [`@NonNull`](https://projectlombok.org/features/NonNull).

> Lombok has always treated various annotations generally named @NonNull on a field as a signal to generate a null-check if lombok generates an entire method or constructor for you, via for example @Data.

**groovy**

Groovy has [@NullCheck](https://docs.groovy-lang.org/3.0.4/html/gapi/groovy/transform/NullCheck.html) which provides similar capabilities.

> Class, method or constructor annotation which indicates that each parameter should be checked to ensure it isn't null. If placed at the class level, all explicit methods and constructors will be checked.

Lombok has several advantages over groovy. With lombok, if a field is marked with `@NonNull` all generated methods will perform null checks. In groovy this is not the case. `includeGenerated` must be set to true for groovy to generate null checks in generated code. When this option is applied in groovy code may still not have a null check. This issue appears to be fixed in groovy 4.

Lombok does not support `@NonNull` at the class level. This may be considered a disadvantage for some. Each parameter for non-generated methods must be explicitly declared as `@NonNull`. Lombok does guarantee that null checks will be created for all generated code.

# @Cleanup

**lombok**

> You can use [`@Cleanup`](https://projectlombok.org/features/Cleanup) to ensure a given resource is automatically cleaned up before the code execution path exits your current scope.

**groovy**

This feature is not supported by groovy although groovy does support additional idioms for [automatic resource management](https://groovy-lang.org/differences.html#_arm_blocks) with the use of closures.

# @Getter and @Setter

**lombok**

> You can annotate any field with [`@Getter`](https://projectlombok.org/features/GetterSetter) and/or [`@Setter`](https://projectlombok.org/features/GetterSetter), to let lombok generate the default getter/setter automatically.

Lombok will generate getters and setters for all fields marked with these annotations. If the class is marked with these annotations all fields will have getters and setters generated. A developer may still supply one of these methods and lombok will keep the original method.

**groovy**

Getters and setters are automatically generated for [properties](http://groovy-lang.org/objectorientation.html#properties) in a groovy class. The getter and setter can be overridden by writing it in the class. Scope can be changed by overriding the method. Properties marked with `final` will not generate a setter.

# @ToString

**lombok**

> Any class definition may be annotated with [`@ToString`](https://projectlombok.org/features/ToString) to let lombok generate an implementation of the toString() method. By default, it'll print your class name, along with each field, in order, separated by commas.

**groovy**

Groovy has its own [`@ToString`](https://docs.groovy-lang.org/latest/html/gapi/groovy/transform/ToString.html) annotation. This is an [ast](https://groovy-lang.org/metaprogramming.html#_available_ast_transformations) which generates the `toString()` method for a class.

# @EqualsAndHashCode

**lombok**

> Any class definition may be annotated with [`@EqualsAndHashCode`](https://projectlombok.org/features/EqualsAndHashCode) to let lombok generate implementations of the equals(Object other) and hashCode() methods.

**groovy**

Groovy provides a similar [`@EqualsAndHashCode`](https://docs.groovy-lang.org/latest/html/gapi/groovy/transform/EqualsAndHashCode.html) annotation. This [ast](https://groovy-lang.org/metaprogramming.html#_available_ast_transformations) creates an `equals()` and `hashCode()` method. It has similar options to lombok.

# @NoArgsConstructor, @RequiredArgsConstructor, @AllArgsConstructor

**lombok**

These annotations create constructors for the class. Required args is any final or uninitialized field with the `@NonNull` annotation.

**groovy**

Groovy provides [`@TupleConstructor`](https://docs.groovy-lang.org/latest/html/gapi/groovy/transform/TupleConstructor.html) which is able to create one constructor with a specific configuration.

It is not possible to create multiple constructors on one class with `@TupleConstructor`. This is the advantage of having multiple annotations in lombok.

# @Data

**lombok**

> [`@Data`](https://projectlombok.org/features/Data) is a convenient shortcut annotation that bundles the features of @ToString, @EqualsAndHashCode, @Getter / @Setter and @RequiredArgsConstructor together: In other words, @Data generates all the boilerplate that is normally associated with simple POJOs (Plain Old Java Objects) and beans: getters for all fields, setters for all non-final fields, and appropriate toString, equals and hashCode implementations that involve the fields of the class, and a constructor that initializes all final fields, as well as all non-final fields with no initializer that have been marked with @NonNull, in order to ensure the field is never null.

**groovy**

Groovy has the [`@Cononical`](https://docs.groovy-lang.org/3.0.4/html/gapi/groovy/transform/Canonical.html) AST which combines `@EqualsAndHashCode`, `@ToString`, and `@TupleConstructor`.

# @Value

**lombok**

> [`@Value`](https://projectlombok.org/features/Value) is the immutable variant of @Data; all fields are made private and final by default, and setters are not generated. The class itself is also made final by default, because immutability is not something that can be forced onto a subclass.

**groovy**

Groovy provides the [@Immutable](https://docs.groovy-lang.org/latest/html/gapi/groovy/transform/Immutable.html) annotation.

# @Builder

**lombok**

> The [`@Builder`](https://projectlombok.org/features/Builder) annotation produces complex builder APIs for your classes.

**groovy**

Groovy provides the [`@Builder`](https://docs.groovy-lang.org/latest/html/gapi/groovy/transform/builder/Builder.html) annotation.

# @SnekyThrows

**lombok**

> [`@SneakyThrows`](https://projectlombok.org/features/SneakyThrows) can be used to sneakily throw checked exceptions without actually declaring this in your method's throws clause.

**groovy**

In groovy all exceptions are optional and do not need to be declared.

# @Synchronized

**lombok**

> [`@Synchronized`](https://projectlombok.org/features/Synchronized) is a safer variant of the synchronized method modifier.

**groovy**

[`@Synchronized`](https://docs.groovy-lang.org/latest/html/gapi/groovy/transform/Synchronized.html) already exists in groovy and works in exactly the same way.

# @With

**lombok**

> The next best alternative to a setter for an immutable property is to construct a clone of the object, but with a new value for this one field. A method to generate this clone is precisely what [`@With`](https://projectlombok.org/features/With) generates: a withFieldName(newValue) method which produces a clone except for the new value for the associated field.

**groovy**

Similar methods to @With can be created in groovy with @Builder but the object is not immutable.

Groovy provides the [`@Builder`](https://docs.groovy-lang.org/latest/html/gapi/groovy/transform/builder/Builder.html) annotation which can be used with a [Simple Strategy](https://docs.groovy-lang.org/latest/html/gapi/groovy/transform/builder/SimpleStrategy.html) to create chained setters.

```
 @Builder(builderStrategy=SimpleStrategy, prefix = 'with')
```

# @Getter(lazy=true)

**lombok**

The [`@Getter(lazy=true)`](https://projectlombok.org/features/GetterLazy) annotation creates a cached version of a getter method.

> You can let lombok generate a getter which will calculate a value once, the first time this getter is called, and cache it from then on.

**groovy**

It is possible to use [`@Memoized`](https://docs.groovy-lang.org/latest/html/gapi/groovy/transform/Memoized.html).

# @Log

**lombok**

> You put the variant of [`@Log`](https://projectlombok.org/features/log) on your class (whichever one applies to the logging system you use); you then have a static final log field, initialized as is the commonly prescribed way for the logging framework you use, which you can then use to write log statements.

**groovy**

Groovy provides [`@Log`](https://docs.groovy-lang.org/latest/html/gapi/groovy/util/logging/Log.html), [`@Log4j`](https://docs.groovy-lang.org/latest/html/gapi/groovy/util/logging/Log4j.html), and [`@Log4j2`](https://docs.groovy-lang.org/latest/html/gapi/groovy/util/logging/Log4j2.html).