Menu
Introduction à la librairie Lombok Java

Introduction à la librairie Lombok Java

Par Sylvain CHAUVET

16.12.2022

Boilerplate !

En voilà un bien beau mot pour commencer un article.

Mais qu’est-ce que du code boilerplate ? Et comment réduire son utilisation en Java ?

Voici tout de suite quelques éléments de réponse !

Le code boilerplate est un code répétitif, dupliqué (ou presque) à plusieurs endroits d’une application. L’exemple typique en Java se situe dans les classes codant les POJO (Plain Old Java Object) où l’on retrouve la plupart du temps des setters, des getters, des constructeurs, … qui sont assez peu différents les uns des autres.

Ces parties de code, bien qu’essentielles au bon fonctionnement d’une application, sont à la fois ennuyeuses à écrire pour les développeurs (même si certains IDE sont tout à fait capables de les générer) et alourdissent la lecture et les potentielles futures modifications du code.

Si vous développez en Java, vous vous êtes sûrement déjà dit en écrivant vos POJO qu’il serait agréable de s’affranchir des sempiternels getters, setters, constructeurs, equals, hash, toString !

Une librairie existe justement pour ça, son nom : Lombok.

Je vais donc dans la suite de cet article vous présenter cette librairie. J’aborderai également l’utilisation des records (fonctionnalité preview de Java 14, standard à partir de Java 16).

Mais avant tout, puisque quelques images valent mieux qu’un long discours, voici un avant/après utilisation de Lombok sur un POJO classique :

Avant :
    import java.math.BigDecimal;
import java.util.Objects;

public class MaterialWithoutLombok {

    private int id;
    private String name;
    private BigDecimal price;

    public MaterialWithoutLombok(int id, String name, BigDecimal price) {
        this.id = id;
        this.name = name;
        this.price = price;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public BigDecimal getPrice() {
        return price;
    }

    public void setPrice(BigDecimal price) {
        this.price = price;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof MaterialWithoutLombok)) return false;
        MaterialWithoutLombok that = (MaterialWithoutLombok) o;
        return getId() == that.getId() && Objects.equals(getName(), that.getName())
                && Objects.equals(getPrice(), that.getPrice());
    }

    @Override
    public int hashCode() {
        return Objects.hash(getId(), getName(), getPrice());
    }

    @Override
    public String toString() {
        return "MaterialWithoutLombok{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", price=" + price +
                '}';
    }
}
Après
    import lombok.AllArgsConstructor;
import lombok.Data;
import java.math.BigDecimal;

@Data
@AllArgsConstructor
public class MaterialWithLombok {

    private int id;
    private String name;
    private BigDecimal price;

}

Ça fait envie non ?  Alors continuons !

 

Lombok

Présentation

Comme je vous le disais en introduction, Lombok est une librairie Java qui a été conçue pour éviter aux développeurs de devoir passer du temps à écrire les méthodes redondantes telles que les getters, setters, …, le tout grâce à l’utilisation d’annotations.
Dans les parties suivantes, nous allons voir comment la mettre en œuvre dans un projet, comment l’intégrer dans notre IDE, ainsi que les annotations principales. Nous finirons par les avantages et les inconvénients de l’outil.

 

Mise en œuvre

Je ne vais détailler ici que la mise en œuvre de Lombok dans les applications Gradle ou Maven, mais il peut également être utilisé sur des applications Ant ou Kobalt.
Lombok étant accessible dans maven central, son intégration à un projet est aisée.
Pour un projet Gradle, il suffit d’ajouter ces lignes dans le build.gradle :
    repositories {
    mavenCentral()
}
dependencies {
    compileOnly 'org.projectlombok:lombok:1.18.24'
    annotationProcessor 'org.projectlombok:lombok:1.18.24'
    testCompileOnly 'org.projectlombok:lombok:1.18.24'
    testAnnotationProcessor 'org.projectlombok:lombok:1.18.24'
}

Pour un projet Maven, c’est tout aussi simple en ajoutant cette fois quelques lignes dans le pom.xml :
        <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.24</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

Maintenant que nous avons déclaré la dépendance dans notre projet, ce serait bien d’intégrer Lombok à notre IDE non ?
Ça tombe bien, c’est la prochaine partie !

 

Intégration dans l’IDE


L’intégration de l’outils Lombok aux IDE les plus couramment utilisés, j’ai nommé Eclipse et IntelliJ, ne présente pas de difficulté particulière. Il est à noter que Lombok est également compatible avec les variantes d’Eclipse (MyEclipse, Spring Tool Suite, JBoss Developer Studio, Red Hat JBoss Developer Studio), ainsi que Netbeans et Visual Studio Code.

IntelliJ

À partir de la version 2020.3 d’IntelliJ vous n’avez rien à faire (quand je vous disais qu’il n’y avait pas de difficulté …).
Pour les versions précédentes, il suffit de se rendre dans les paramétrages d’IntelliJ, dans la partie Plugins, de chercher le plugin Lombok, de l’installer, puis de redémarrer l’IDE. Rien de bien sorcier.

Eclipse (et ses variantes)

Pour installer Lombok dans Eclipse ou une de ses variantes, il faut télécharger le Lombok.jar sur le site de Lombok ou sur le repository Maven, puis double-cliquer sur le jar (ou le lancer en ligne de commande via java -jar lombok.jar). L’assistant d’installation va aller rechercher les versions d’Eclipse sur votre poste puis vous proposer d’installer Lombok sur ces versions, et voilà, le tour est joué !

Annotations principales

Comme je l’écrivais plus haut, le fonctionnement de Lombok se base sur l’utilisation d’annotations. Je ne vais pas présenter dans cet article toutes les annotations, mais seulement les principales. De même, je ne rentrerai pas dans le détail de chaque annotation présentée, le but étant de faire un petit tour d’horizon. De plus, l’équipe Lombok à très bien décrit toutes ces annotations, avec humour, et avec des exemples clairs. Il serait dommage que je vous prive d’aller lire leurs explications en vous en donnant trop ici 😉.

 

Annotation à placer au-dessus de la classe :

  • @NoArgsConstructor: Génère un constructeur sans argument
  • @RequiredArgsConstructor : Génère un constructeur prenant en arguments tous les attributs finaux ou marqués comme @NonNull et n’étant pas initialisés
  • @AllArgsConstructor: Ajoute un constructeur prenant en arguments tous les attributs du POJO
  • @ToString : Ajoute une méthode toString() à la classe. Il existe des options, permettant par exemple de spécifier les attributs à inclure, ou bien d’en exclure certains.
  • @EqualsAndHashCode: Ajoute les méthodes equals() et hashCode() à la classe. Comme pour l’annotation @ToString, les attributs peuvent être spécifiés ou exclus.
  • @Data: Cette annotation est une agrégation des annotations @ToString, @EqualsAndHashCode, @Getter, @Setter et @RequiredArgsConstructor. Elle prend les paramètres par default de toutes ces annotations, qui peuvent cependant être surchargées. Par exemple, si l’annotation @Data est utilisée en même temps que l’annotation @ToString avec un attribut exclu, la méthode toString() générée sera celle sans l’attribut exclu. Cette annotation, bien que tentante, doit cependant être utilisée en gardant en tête qu’elle va potentiellement générer des méthodes qui ne sont pas forcément utiles (comme les setters)

 

Annotations à placer au-dessus de la classe ou au-dessus d’un attribut

  • @Getter : Placée au-dessus de la classe, cette annotation permet de générer un getter pour tous les attributs de la classe. Au-dessus d’un attribut, le getter sera généré seulement pour l’attribut en question. La visibilité des getters générés peux être modifiée en spécifiant un AccessLevel, par exemple : @Getter(AccessLevel.PROTECTED)
  • @Setter : Cette annotation s’utilise de la même manière que le @Getter et permet de générer les setters des attributs

Annotation à placer au-dessus d’un attribut ou devant un paramètre de méthode

  • @NonNull : Si cette annotation est placée au-dessus d’un attribut, elle permet d’ajouter ce dernier aux paramètres d’un constructeur généré par @RequiredArgsConstructor. Si l’attribut a un setter, Lombok va également générer un contrôle de nullité sur ce setter et déclencher un NullPointerException si le setter est utilisé avec un paramètre null. De la même manière, si cette annotation est utilisée devant un paramètre de méthode, un NullPointerException sera généré si la méthode est appelée avec ce paramètre à null.

 

Pros & Cons

Comme vous avez pu le lire jusqu’à présent, Lombok a l’avantage de rendre l’écriture (et la lecture) du code beaucoup plus fluide et efficace. Il faut cependant garder quelques points importants à l’esprit :

  • Les méthodes générées par Lombok n’étant pas visibles dans les sources, le développeur n’a pas la possibilité de mettre un point d’arrêt dans ces dernières afin de debugger son code.
  • Pour la même raison, la javadoc ne peux pas être autogénérée.
  • Il y a une dépendance forte du code à la librairie Lombok.
  • Une méconnaissance des implémentations que va faire Lombok peut entrainer une différence entre le comportement réel d’une méthode et celui attendu par le développeur.
  • Une perte de contrôle sur le code peux être rencontrée, particulièrement avec une surutilisation du @Data alors que toutes les méthodes qui vont être générées ne sont pas forcément utiles/désirées, comme les setters par exemple.



Pour adresser les 4 premiers points, l’équipe du projet Lombok a développé l’outil Delombok qui prend en entrée un code source utilisant Lombok et qui génère un code source Java classique. C’est-à-dire que si vous avez une classe avec l’annotation Lombok @AllArgsConstructor, la classe générée par l’outil Delombok comportera un constructeur ayant en arguments tous les attributs de la classe.

Cet outil permet donc de voir ce qu’il se passe « sous le capot » de Lombok et rend possible la visualisation claire des implémentations que fait Lombok, le debuggage du code via des points d’arrêt ainsi que la génération de javadoc à partir du code « Delomboké ».

Des plugins maven et gradle existent également pour « Delomboker » automatiquement le code source lors de la phase de build afin d’utiliser la librairie Lombok lors de la phase de développement tout en livrant en production un code indépendant de la librairie.

En revanche, le code généré par Delombok peut réserver quelques surprises de qualimétrie. Si l’on reprend l’exemple d’une classe avec l’annotation @AllArgsConstructor, et que cette classe à de nombreux attributs, le constructeur généré va être l’objet d’une alerte lors de l’analyse du code à cause de ses trop nombreux paramètres.

Concernant le dernier point, la seule parade est une prise de conscience du développeur sur le lien entre ce qu’il fait avec les annotations qu’il utilise et ce dont il a réellement besoin. Comme le dirait William Lamb (ou Ben Parker, selon vos références) : « With great power comes great responsibility ! ».

Les Records


Les records sont un type spécial de classe introduits en mode preview dans Java 14, et en standard depuis Java 16.

Un record génère une classe immuable dont les méthodes equals(), hashCode(), toString(), ainsi que les getters et un constructeur ayant comme argument tous les attributs du record sont auto-générés.

Des méthodes peuvent être définies dans les records, on peut par exemple ajouter un constructeur n’ayant pas tous les attributs comme argument.

Si nous reprenons l’exemple du début de cet article, nous obtiendrions ce type de code :

    import java.math.BigDecimal;

public record MaterialRecord(int id, String name, BigDecimal price) {
}

On peut remarquer que c’est encore plus court qu’en utilisant la librairie Lombok !
Si votre projet est basé sur une version de Java qui vous permet d’utiliser les records, il serait donc dommage de vous en priver !

Je vous vois derrière votre écran, à penser : «Mais donc, si je comprends bien, puisque mon projet est en Java 18, la lecture de cet article n’a été qu’une incommensurable perte de temps ??? »

Ce à quoi je vous répondrais « Que nenni ! ».

En effet, le caractère immuable des records est un frein dans de nombreux usages, où nos objets Java doivent vivre et être modifiés, dans ces cas là Lombok garde tout son attrait 😊.

 

Sources

Pour aller plus loin, vous trouverez de plus amples informations sur l’installation de Lombok, les différentes annotations déjà présentes et celles à venir, … sur le site officiel.

Concernant les records, vous pourrez trouver la documentation Oracle ici.

Retour aux articles

C'est à lire...