Prise en charge de JPA 2.2 pour les types de date / heure Java 8

1. Vue d'ensemble

La version JPA 2.2 a officiellement introduit la prise en charge de l'API Java 8 Date and Time . Avant cela, soit nous devions nous fier à une solution propriétaire, soit nous devions utiliser l'API JPA Converter.

Dans ce didacticiel, nous montrerons comment mapper les différents types de date et d' heure Java 8 . Nous nous concentrerons en particulier sur ceux qui prennent en compte les informations de décalage.

2. Dépendances de Maven

Avant de commencer, nous devons inclure l'API JPA 2.2 dans le chemin de classe du projet. Dans un projet basé sur Maven, nous pouvons simplement ajouter sa dépendance à notre fichier pom.xml :

 javax.persistence javax.persistence-api 2.2 

De plus, pour exécuter le projet, nous avons besoin d'une implémentation JPA et du pilote JDBC de la base de données avec laquelle nous allons travailler. Dans ce tutoriel, nous utiliserons EclipseLink et la base de données PostgreSQL:

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

N'hésitez pas à consulter les dernières versions de l'API JPA, d'EclipseLink et du pilote JDBC PostgreSQL sur Maven Central.

Bien sûr, nous pouvons utiliser d'autres bases de données ou implémentations JPA comme Hibernate.

3. Prise en charge de TimeZone

Nous pouvons travailler avec n'importe quelle base de données, mais d'abord, nous devons vérifier la prise en charge de ces types SQL standard, car le JDBC 4.2 est basé sur:

  • HORAIRE (n) AVEC FUSEAU HORAIRE
  • HORAIRE (n) SANS FUSEAU HORAIRE
  • HEURE (n) AVEC FUSEAU HORAIRE
  • HEURE (n) SANS FUSEAU HORAIRE

Ici, n est la précision des fractions de seconde et est compris entre 0 et 9 chiffres. SANS FUSEAU HORAIRE est facultatif et peut être omis. Si WITH TIME ZONE est spécifié, le nom du fuseau horaire ou le décalage par rapport à UTC est requis.

Nous pouvons représenter le fuseau horaire dans l'un de ces deux formats:

  • Nom du fuseau horaire
  • Décalage de UTC ou de la lettre Z pour UTC

Pour notre exemple, nous avons choisi la base de données PostgreSQL grâce à sa prise en charge complète du type SQL TIME WITH TIME ZONE .

Notez que d'autres bases de données peuvent ne pas prendre en charge ces types.

4. Mappage des types de date avant Java 8

Avant Java 8, nous devions généralement mapper les types SQL génériques TIME, DATE et TIMESTAMP aux classes java.sql . * Java.sql.Time , java.sql.Date et java.sql.Timestamp, respectivement, ou java.util types java.util.Date et java.util.Calendar .

Voyons d' abord comment utiliser les types java.sql . Ici, nous définissons simplement les attributs avec des types java.sql dans le cadre d'une classe @Entity :

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

Alors que les types java.sql fonctionnent comme tous les autres types sans aucun mappage supplémentaire, les types java.util doivent spécifier les types temporels correspondants.

Cela se fait via l' annotation @Temporal dont l' attribut value nous permet de spécifier le type JDBC correspondant, en utilisant l' énumération 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;

Notez que si nous utilisons Hibernate comme implémentation, cela ne prend pas en charge le mappage du calendrier à TIME .

De même, nous pouvons utiliser la classe Calendar :

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

Aucun de ces types ne prend en charge le fuseau horaire ou le décalage. Pour traiter ces informations, nous devions traditionnellement stocker l'heure UTC.

5. Mappage des types de date Java 8

Java 8 a introduit les packages java.time et l'API JDBC 4.2 a ajouté la prise en charge des types SQL supplémentaires TIMESTAMP WITH TIME ZONE et TIME WITH TIME ZONE .

Nous pouvons maintenant cartographier les types JDBC TIME, DATE, et TIMESTAMP aux java.time types - LocalTime, LocalDate et 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;

De plus, nous prenons en charge le fuseau horaire local décalé vers UTC via les classes OffsetTime et 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;

Les types de colonnes mappées correspondants doivent être TIME WITH TIME ZONE et TIMESTAMP WITH TIME ZONE . Malheureusement, toutes les bases de données ne prennent pas en charge ces deux types.

Comme nous pouvons le voir, JPA prend en charge ces cinq classes en tant que types de base, et aucune information supplémentaire n'est nécessaire pour faire la distinction entre les informations de date et / ou d'heure.

Après avoir enregistré une nouvelle instance de notre classe d'entité, nous pouvons vérifier que les données ont été insérées correctement:

6. Conclusion

Avant Java 8 et JPA 2.2, les développeurs devaient généralement convertir les types de date / heure en UTC avant de les conserver. JPA 2.2 prend désormais en charge cette fonctionnalité prête à l'emploi en prenant en charge le décalage par rapport à UTC et en tirant parti de la prise en charge de JDBC 4.2 pour le fuseau horaire.

Le code source complet de ces exemples est disponible à l'adresse over sur Github.