POJO più smart con Project Lombok

Project Lombok, ovvero uno dei tanti modi per non reinventare la ruota nei nostri progetti

Esistono tante cose che spesso vengono ripetute quando si programma in Java, come i classici metodi get/set, i controlli sulle variabili nulle etc. etc. Project Lombok è un insieme di annotation che possono aiutarci a rendere il nostro codice sorgente più snello, senza dover appunto perdere tempo dietro quelle classiche cose che facciamo all’interno della nostre classi Java. Per aggiungere la libreria al nostro progetto basta aggiungere la seguente dipendenza

<dependency>
	<groupId>org.projectlombok</groupId>
	<artifactId>lombok</artifactId>
	<version>1.16.4</version>
</dependency>

Qui di seguito vengono analizzate una per una le annotation presenti in questo utile progetto opensource.

 

@NonNull

Questa annotation permette a Lombok di generare un classico metodo di verifica della variabile, per lanciare quindi un NullPointerException in cui venga indicato precisamente qual’è la variabile nulla

public void stampa(@NonNull String stringaDaSegnalare) {
   System.out.println(stringaDaSegnalare.charAt(0));
}

richiamando il metodo con un null avremo il seguente errore

Exception in thread "main" java.lang.NullPointerException: stringaDaSegnalare

 

@ToString

Quanto volte vi è capitato di dover scrivere il metodo toString delle vostre classi? Perchè non utilizzare qualcosa che per default vi genera un metodo toString sensato rispetto alle caratteristiche della vostra classe? Lombok ci aiuta in questo con l’annotation @ToString. Il POJO d’esempio è il seguente

package com.javastaff.lombok;

import lombok.ToString;

@ToString
public class Utente {
    private int id;
    private String nome;
    private String cognome;

    public int getId() {
        return id;
    }

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

    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    public String getCognome() {
        return cognome;
    }

    public void setCognome(String cognome) {
        this.cognome = cognome;
    }
}

La classe è annotata con @ToString, quindi ora quando andremo ad eseguire il seguente codice

Utente utente=new Utente();
utente.setId(123);
utente.setNome("Federico");
utente.setCognome("Paparoni");
System.out.println(utente);

avremo per magia la seguente stringa nell’output

Utente(id=123, nome=Federico, cognome=Paparoni)

Praticamente vengono recuperati tutti i campi della classe e utilizzati per costruire il toString. Se volessimo escludere dei campi, perchè magari sono inutili a livello di logging, baste specificarlo nell’annotation @ToString(exclude=”id”)

 

@EqualsAndHashCode

Ogni classe può essere annotata con @EqualsAndHashCode per generare l’implementazione di equals e hashCode relative. Come impostazione di default vengono utilizzati tutti i campi non statici e non transient, ma in aggiunta possono essere specificati altri campi da escludere. Se nella classe Utente volessimo escludere il nome allora andremmo a scrivere l’annotation nel seguente modo

@EqualsAndHashCode(exclude="nome")

 

@Getter / @Setter

Immagino che qualsiasi IDE stiate utilizzando, conosciate la shortcut per generare automaticamente tutti i campi get/set in un POJO. Queste due annotation sono una soluzione veloce ed elegante per tanto codice che viene sempre scritto e per rendersene conto basta confrontare la classe Utente riportata precedentemente con la seguente

package com.javastaff.lombok;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class Utente {
    private int id;
    private String nome;
    private String cognome;
}

I metodi vengono generati automaticamente e quindi utilizzando la classe esternamente non ci rendiamo nemmeno conto che in realtà non sono fisicamente presenti i metodi.

 

@NoArgsConstructor, @RequiredArgsConstructor and @AllArgsConstructor

Queste annotazioni ci permettono di gestire alcune classiche situazioni riguardanti i costruttori della nostra classe.

  • @NoArgsConstructor : genera un costruttore senza parametri. Nei casi in cui siano presenti delle variabili final verrà generato un errore, mentre i campi annotati con @NotNull non saranno controllati
  • @RequiredArgsConstructor : genera un costruttore con un parametro per ogni campo che richiedere una gestione particolare come i campi final, quelli annotati con @NotNull
  • @AllArgsConstructor : genera un costruttore con tutti i campi preseni nella classe

 

@Data

Tutto quello che abbiamo visto nelle annotation @ToString, @EqualsAndHashCode, @Getter, @Setter e @RequiredArgsConstructor lo possiamo avere con questa singola annotation

package com.javastaff.lombok;

import lombok.Data;

@Data
public class Utente {
    private int id;
    private String nome;
    private String cognome;
}

Pratico no?

 

@Cleanup

Nel codice dei nostri metodi Java ci dobbiamo spesso occupare di chiudere gli stream di I/O, le connessioni al database e altri oggetti che mantengono una connessione attiva. Quindi il nostro classico codice è il seguente

try {
    OutputStream out = new FileOutputStream(args[1]);
    ...
    ...
} finally {
    if (out != null) {
	out.close();
    }
}

Utilizzando l’annotation @Cleanup, non dovremo andare ad inserire quella classica sbrodolata di try/finally perchè sarà generata automaticamente da Lombok. Quindi il nostro codice diventerà semplicemente

@Cleanup
OutputStream out = new FileOutputStream(args[1]);

 

@Value

@Value è la versione immutabile di @Data; annotando una classe con questa annotation tutti i campi diventano private e final. I metodi set non vengono generati e la classe stessa diventa final.

 

@Builder

Utilizzando l’annotation @Builder nel vostro POJO, verrà costruita dinamicamente tutta la gestione stile builder per la vostra classe. Quindi con questa semplice annotation sarà possibile scrivere codice come il seguente

Utente utente=Utente.builder().cognome("Paparoni").nome("Federico").build();

 

@SneakyThrows

Utilizzando questa annotation su un metodo è possibile nascondere il fatto che venga sollevata una specifica checked exception. E’ un costrutto un pò particolare ma in alcuni casi potrebbe trovare il suo utilizzo.

@Synchronized

Permette di scrivere un blocco synchronized come il modificatore, ma invece di bloccare l’esecuzione sul this la blocca su un Object $lock che viene aggiunto alla classe.

 

@Log

Questa annotazione permette di definire a livello di classe che sarà disponibile un log e quindi permette di richiamare questo oggetto all’interno della classe. Il vero e proprio log che sarà generato dinamicamente dipende dall’annotation di log che utilizzeremo (ognuna genera un log con una libreria differente)

@CommonsLog
private static final org.apache.commons.logging.Log log = 
   org.apache.commons.logging.LogFactory.getLog(LogExample.class);
@Log
private static final java.util.logging.Logger log = 
   java.util.logging.Logger.getLogger(LogExample.class.getName());
@Log4j
private static final org.apache.log4j.Logger log = 
   org.apache.log4j.Logger.getLogger(LogExample.class);
@Log4j2
private static final org.apache.logging.log4j.Logger log = 
   org.apache.logging.log4j.LogManager.getLogger(LogExample.class);
@Slf4j
private static final org.slf4j.Logger log = 
   org.slf4j.LoggerFactory.getLogger(LogExample.class);
@XSlf4j
private static final org.slf4j.ext.XLogger log = 
   org.slf4j.ext.XLoggerFactory.getXLogger(LogExample.class);

 

Federico Paparoni

Looking for a right "about me"...