Una guida alla libreria dei tipi di ibernazione

1. Panoramica

In questo tutorial, daremo uno sguardo ai tipi di ibernazione. Questa libreria ci fornisce alcuni tipi che non sono nativi nel core Hibernate ORM.

2. Dipendenze

Per abilitare i tipi di ibernazione, aggiungeremo semplicemente la dipendenza dei tipi di ibernazione appropriata :

 com.vladmihalcea hibernate-types-52 2.9.7  

Funzionerà con le versioni di Hibernate 5.4, ​​5.3 e 5.2.

Nel caso in cui la versione di Hibernate sia precedente, il valore artifactId sopra sarà diverso. Per le versioni 5.1 e 5.0, possiamo usare hibernate-types-51. Allo stesso modo, la versione 4.3 richiede hibernate-types-43 e le versioni 4.2 e 4.1 richiedono hibernate-types-4.

Gli esempi in questo tutorial richiedono un database. Utilizzando Docker abbiamo fornito un contenitore di database. Pertanto, avremo bisogno di una copia funzionante di Docker.

Quindi, per eseguire e creare il nostro database dobbiamo solo eseguire:

$ ./create-database.sh

3. Database supportati

Possiamo utilizzare i nostri tipi con database Oracle, SQL Server, PostgreSQL e MySQL. Pertanto, la mappatura dei tipi in Java ai tipi di colonne del database varierà a seconda del database che utilizziamo. Nel nostro caso, useremo MySQL e mapperemo JsonBinaryType a un tipo di colonna JSON.

La documentazione sulle mappature supportate può essere trovata nel repository di Hibernate Types.

4. Modello di dati

Il modello di dati per questo tutorial ci consentirà di memorizzare informazioni su album e canzoni. Un album ha una copertina e una o più canzoni. Una canzone ha un artista e una durata. La copertina ha due URL immagine e un codice UPC. Infine, un artista ha un nome, un paese e un genere musicale.

In passato, avremmo creato tabelle per rappresentare tutti i dati nel nostro modello. Ma ora che abbiamo i tipi disponibili possiamo archiviare molto facilmente alcuni dati come JSON.

Per questo tutorial, creeremo solo tabelle per gli album e le canzoni:

public class Album extends BaseEntity { @Type(type = "json") @Column(columnDefinition = "json") private CoverArt coverArt; @OneToMany(fetch = FetchType.EAGER) private List songs; // other class members }
public class Song extends BaseEntity { private Long length = 0L; @Type(type = "json") @Column(columnDefinition = "json") private Artist artist; // other class members }

Utilizzando JsonStringType rappresenteremo la copertina e gli artisti come colonne JSON in quelle tabelle:

public class Artist implements Serializable { private String name; private String country; private String genre; // other class members }
public class CoverArt implements Serializable { private String frontCoverArtUrl; private String backCoverArtUrl; private String upcCode; // other class members }

È importante notare che le classi Artist e CoverArt sono POJO e non entità. Inoltre, sono membri delle nostre classi di entità del database, definite con l' annotazione @Type (type = “json”) .

4.1. Archiviazione di tipi JSON

Abbiamo definito i nostri modelli di album e brani per contenere i membri che il database memorizzerà come JSON. Ciò è dovuto all'utilizzo del tipo json fornito . Per avere quel tipo disponibile per l'uso dobbiamo definirlo utilizzando una definizione di tipo:

@TypeDefs({ @TypeDef(name = "json", typeClass = JsonStringType.class), @TypeDef(name = "jsonb", typeClass = JsonBinaryType.class) }) public class BaseEntity { // class members }

Il @type per JsonStringType e JsonBinaryType rende i tipi JSON e jsonb disponibili.

Le ultime versioni di MySQL supportano JSON come tipo di colonna. Di conseguenza, JDBC elabora qualsiasi JSON letto da o qualsiasi oggetto salvato in una colonna con uno di questi tipi come String . Ciò significa che per mappare correttamente alla colonna dobbiamo utilizzare JsonStringType nella nostra definizione del tipo.

4.2. Ibernazione

Infine, i nostri tipi si tradurranno automaticamente in SQL utilizzando JDBC e Hibernate. Quindi, ora possiamo creare alcuni oggetti canzone, un oggetto album e conservarli nel database. Successivamente, Hibernate genera le seguenti istruzioni SQL:

insert into song (name, artist, length, id) values ('A Happy Song', '{"name":"Superstar","country":"England","genre":"Pop"}', 240, 3); insert into song (name, artist, length, id) values ('A Sad Song', '{"name":"Superstar","country":"England","genre":"Pop"}', 120, 4); insert into song (name, artist, length, id) values ('A New Song', '{"name":"Newcomer","country":"Jamaica","genre":"Reggae"}', 300, 6) insert into album (name, cover_art, id) values ('Album 0', '{"frontCoverArtUrl":"//fakeurl-0","backCoverArtUrl":"//fakeurl-1","upcCode":"b2b9b193-ee04-4cdc-be8f-3a276769ab5b"}', 7) 

Come previsto, i nostri oggetti Java di tipo json sono tutti tradotti da Hibernate e memorizzati come JSON ben formati nel nostro database.

5. Memorizzazione di tipi generici

Oltre a supportare le colonne basate su JSON, la libreria aggiunge anche alcuni tipi generici: YearMonth , Year e Month dal pacchetto java.time .

Ora possiamo mappare questi tipi che non sono supportati nativamente da Hibernate o JPA . Inoltre, ora abbiamo la possibilità di memorizzarli come colonne Integer , String o Date .

Ad esempio, supponiamo di voler aggiungere la data di registrazione di una canzone al nostro modello di canzone e memorizzarla come numero intero nel nostro database. Possiamo usare YearMonthIntegerType nella nostra definizione di classe di entità Song :

@TypeDef( typeClass = YearMonthIntegerType.class, defaultForType = YearMonth.class ) public class Song extends BaseEntity { @Column( name = "recorded_on", columnDefinition = "mediumint" ) private YearMonth recordedOn = YearMonth.now(); // other class members } 

Il nostro recordedOn valore della proprietà è tradotto al typeClass abbiamo fornito. Di conseguenza, un convertitore predefinito manterrà il valore nel nostro database come numero intero .

6. Altre classi di utilità

Hibernate Types ha alcune classi helper che migliorano ulteriormente l'esperienza dello sviluppatore quando si utilizza Hibernate.

Il CamelCaseToSnakeCaseNamingStrategy mappe proprietà cammello prima lettera maiuscola nelle nostre classi Java alle colonne di serpente-cased nel nostro database.

Il ClassImportIntegrator permette semplici valori del nome classe Java DTO in parametri del costruttore JPA.

Ci sono anche le classi ListResultTransformer e MapResultTransformer che forniscono implementazioni più pulite degli oggetti risultato utilizzati da JPA. Inoltre, supportano l'uso di lambda e forniscono compatibilità con le versioni precedenti di JPA.

7. Conclusione

In questo tutorial, abbiamo introdotto la libreria Java Hibernate Types e i nuovi tipi che aggiunge a Hibernate e JPA. Abbiamo anche esaminato alcune delle utilità e dei tipi generici forniti dalla libreria.

L'implementazione degli esempi e dei frammenti di codice sono disponibili su GitHub.