Supporto JPA 2.2 per tipi di data / ora Java 8

1. Panoramica

La versione 2.2 di JPA ha introdotto ufficialmente il supporto per Java 8 Date and Time API. Prima di allora, o dovevamo fare affidamento su una soluzione proprietaria, o dovevamo utilizzare l'API del convertitore JPA.

In questo tutorial, mostreremo come mappare i vari tipi di data e ora di Java 8 . Ci concentreremo in particolare su quelli che tengono conto delle informazioni di offset.

2. Dipendenze di Maven

Prima di iniziare, è necessario includere l'API JPA 2.2 nel classpath del progetto. In un progetto basato su Maven, possiamo semplicemente aggiungere la sua dipendenza al nostro file pom.xml :

 javax.persistence javax.persistence-api 2.2 

Inoltre, per eseguire il progetto, abbiamo bisogno di un'implementazione JPA e del driver JDBC del database con cui lavoreremo. In questo tutorial, useremo EclipseLink e il database PostgreSQL:

 org.eclipse.persistence eclipselink 2.7.4 runtime   org.postgresql postgresql 42.2.5 runtime bundle 

Sentiti libero di controllare le ultime versioni dell'API JPA, EclipseLink e del driver JDBC PostgreSQL su Maven Central.

Naturalmente, possiamo utilizzare altri database o implementazioni JPA come Hibernate.

3. Supporto TimeZone

Possiamo lavorare con qualsiasi database, ma prima dovremmo controllare il supporto per questi tipi SQL standard, poiché JDBC 4.2 si basa su:

  • TIMESTAMP (n) CON FUSO ORARIO
  • TIMESTAMP (n) SENZA FUSO ORARIO
  • ORA (n) CON FUSO ORARIO
  • ORA (n) SENZA FUSO ORARIO

Qui, n è la precisione frazionaria dei secondi ed è compresa tra 0 e 9 cifre. SENZA FUSO ORARIO è opzionale e può essere omesso. Se viene specificato WITH TIME ZONE, è richiesto il nome del fuso orario o l'offset rispetto a UTC.

Possiamo rappresentare il fuso orario in uno di questi due formati:

  • Nome del fuso orario
  • Offset da UTC o la lettera Z per UTC

Per il nostro esempio, abbiamo scelto il database PostgreSQL grazie al suo pieno supporto per il tipo SQL TIME WITH TIME ZONE .

Tieni presente che altri database potrebbero non supportare questi tipi.

4. Mappatura dei tipi di data prima di Java 8

Prima di Java 8, di solito dovevamo mappare i tipi SQL generici TIME, DATE e TIMESTAMP , rispettivamente alle classi java.sql . * Java.sql.Time , java.sql.Date e java.sql.Timestamp , o per java.util tipo java.util.Date e java.util.Calendar .

Per prima cosa, vediamo come utilizzare i tipi java.sql . Qui stiamo semplicemente definendo gli attributi con i tipi java.sql come parte di una classe @Entity :

@Entity public class JPA22DateTimeEntity { private java.sql.Time sqlTime; private java.sql.Date sqlDate; private java.sql.Timestamp sqlTimestamp; // ... }

Mentre i tipi java.sql funzionano come qualsiasi altro tipo senza alcuna mappatura aggiuntiva, i tipi java.util devono specificare i tipi temporali corrispondenti.

Questo viene fatto tramite l' annotazione @Temporal il cui attributo value ci consente di specificare il tipo JDBC corrispondente, utilizzando l' enumerazione TemporalType :

@Temporal(TemporalType.TIME) private java.util.Date utilTime; @Temporal(TemporalType.DATE) private java.util.Date utilDate; @Temporal(TemporalType.TIMESTAMP) private java.util.Date utilTimestamp;

Tieni presente che se stiamo utilizzando Hibernate come implementazione, questo non supporta la mappatura di Calendar su TIME .

Allo stesso modo, possiamo usare la classe Calendar :

@Temporal(TemporalType.TIME) private Calendar calendarTime; @Temporal(TemporalType.DATE) private Calendar calendarDate; @Temporal(TemporalType.TIMESTAMP) private Calendar calendarTimestamp;

Nessuno di questi tipi supporta il fuso orario o l'offset. Per gestire queste informazioni, tradizionalmente dovevamo memorizzare l'ora UTC.

5. Mappatura dei tipi di data Java 8

Java 8 ha introdotto i pacchetti java.time e l'API JDBC 4.2 ha aggiunto il supporto per i tipi SQL aggiuntivi TIMESTAMP WITH TIME ZONE e TIME WITH TIME ZONE .

Ora possiamo mappare il JDBC Tipi ora, la data e TIMESTAMP ai java.time tipi - LocalTime, LocalDate , e LocalDateTime :

@Column(name = "local_time", columnDefinition = "TIME") private LocalTime localTime; @Column(name = "local_date", columnDefinition = "DATE") private LocalDate localDate; @Column(name = "local_date_time", columnDefinition = "TIMESTAMP") private LocalDateTime localDateTime;

Inoltre, abbiamo il supporto per la differenza tra fuso orario locale e UTC tramite le classi OffsetTime e OffsetDateTime :

@Column(name = "offset_time", columnDefinition = "TIME WITH TIME ZONE") private OffsetTime offsetTime; @Column(name = "offset_date_time", columnDefinition = "TIMESTAMP WITH TIME ZONE") private OffsetDateTime offsetDateTime;

I tipi di colonna mappati corrispondenti devono essere TIME WITH TIME ZONE e TIMESTAMP WITH TIME ZONE . Sfortunatamente, non tutti i database supportano questi due tipi.

Come possiamo vedere, JPA supporta queste cinque classi come tipi di base e non sono necessarie informazioni aggiuntive per distinguere tra le informazioni sulla data e / o sull'ora.

Dopo aver salvato una nuova istanza della nostra classe di entità, possiamo verificare che i dati siano stati inseriti correttamente:

6. Conclusione

Prima di Java 8 e JPA 2.2, gli sviluppatori di solito dovevano convertire i tipi di data / ora in UTC prima di renderli persistenti. JPA 2.2 ora supporta questa funzione immediatamente supportando l'offset rispetto a UTC e sfruttando il supporto JDBC 4.2 per il fuso orario.

Il codice sorgente completo per questi esempi può essere trovato su Github.