Implementare un "entity callback" con SpringBoot e MongoDB

Bassem 27/10



Qualche volta, abbiamo il bisogno di effettuare certe operazioni prima di salvare un dato nel database, come sappiamo per i sql databases Spring fornisce alcuni metodi di "lifecycle callback" come per esempio @PostPersist e @PreUpdate, ma se la nostra applicazione usasse un MongoDb, le precedenti annotazioni non le troveremo nel modulo Spring Data MongoDb. Nonostante ciò il modulo fornisce alcuni Entity Callbacks. In questo articolo vediamo come possiamo utilizzarli.

Ho creato una applicazione classica per accorciare gli Url, in cui ho sfruttato gli"Entity Callbacks". L'applicazione è basata su spring boot e MongoDB come database, Ho deciso di settare l'url corto uguale alle ultime sei cifre del Id del documento /entità. Per conoscenza l'oggetto ObjectId di MongoDB è composto da 4-byte del timestamp attuale, 5-byte di valore casuale e 3-byte di un cantatore il quale è inizializzato con un valore casuale. Per maggiori dettagli, potete vedere la documentazione ufficiale qua.
Il documento da salvare nel database è il seguente:

@Document
public class Url {
    @Id
    private ObjectId id;
    private String fullUrl;
    private String shortUrl;
    private long count;
..
}

Il mio obiettivo principale è quello di settare la proprietà "shortUrl" prima di mandare il dato al database usando una azione "callback".
Il modulo di Spring data mongodb fornisce diversi "callbacks", come ad esempio BeforeConvertCallback, BeforeSaveCallback, e altri. La lista complete può essere trovata qua. Per raggiungere questo obiettivo, andiamo a creare un componente che implementa l'interfaccia BeforeConvertCallback come segue:

@Component
public class UrlListener implements BeforeConvertCallback<Url> {

   @Override
   public Url onBeforeConvert(Url entity, String collection) {
       if (entity.getId() == null) {
           ObjectId id = new ObjectId();
           entity.setId(id);
           entity.setShortUrl(id.toHexString().substring(18, 24));
       }
       return entity;
   }

Questa classe verrà invocata prima che un oggetto Url viene convertito in org.bson.Document (binary json, il formato di rappresentazione usato in MongoDB). Sto usanodo il "beforeConver" perchè per qualche ragione con il "beforeSave" le proprietà modificate con la callabck vengono sostituite da un nuovo ObjectId prima di raggiungere il database.
Esaminiamo questa classe, prima ci assicuriamo che stiamo modificando una entità nuova, ispezionando la proprietà Id. Dopo di che assegniamo uno nuovo oggetto id mediante il costruttore di ObjectId, infine settiamo la proprietà shortUrl con le ultime sei cifre della rappresentazione esadecimale del id.

Tutto qua, il codice dell'applicazione può essere trovato su GitHub. La stessa applicazione è stata anche realizzata con QUARKUS per sfruttare la GraalVM, per migliorare la memoria e i tempi di strat-up, la potete trovare qua.