web-dev-qa-db-fra.com

Prise en charge de JPA pour la nouvelle API de date et heure Java 8

J'utilise Java 8 pour mon nouveau projet.

J'essaie d'utiliser les nouvelles API de date et d'heure dans Java 8, mais je ne sais pas si JPA 2.1 prend pleinement en charge cette nouvelle API de date et d'heure ou non.

Veuillez partager votre expérience/opinion sur les supports JPA pour la nouvelle API de date et heure en Java 8.

Puis-je utiliser de nouvelles API de date et d'heure dans Java 8 en toute sécurité avec JPA 2.1?

METTRE À JOUR:

J'utilise Hibernate (4.3.5.Final) comme implémentation de JPA.

53
TheKojuEffect

JPA 2.1 est une spécification qui est apparue avant Java 1.8, ne vous obligez donc pas à la prendre en charge. Il est évident que certaines implémentations peuvent prendre en charge certaines fonctionnalités de Java 1.8. Certains ont des problèmes avec le bytecode Java 1.8 (par exemple EclipseLink). Je sais que DataNucleus prend en charge Java.time et Java 1.8, car c’est celui que j’utilise. Vous devrez vérifier dans votre implémentation quel est son niveau de support.

Il a été demandé à JPA 2.2 de prendre en charge les types Java.time. Consultez ce problème https://Java.net/jira/browse/JPA_SPEC-63

19
Neil Stockton

Pour Hibernate 5.X, ajoutez simplement

    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-Java8</artifactId>
        <version>${hibernate.version}</version>
    </dependency>

et 

@NotNull
@Column(name = "date_time", nullable = false)
protected LocalDateTime dateTime;

fonctionnera sans aucun effort supplémentaire . Voir https://hibernate.atlassian.net/browse/HHH-8844

METTRE À JOUR:

Regardez le commentaire de Jeff Morin: depuis Hibernate 5.2.x cela suffit

 <dependency>
     <groupId>org.hibernate</groupId>
     <artifactId>hibernate-core</artifactId>
     <version>5.2.1.Final</version>
 </dependency>
 <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-...</artifactId>
     <version>4.3.1.RELEASE</version>
 </dependency>

Voir https://github.com/hibernate/hibernate-orm/wiki/Migration-Guide---5.2 and Intégrez Hibernate 5.2 au framework Spring 4.x

70
GKislin

JPA 2.2 prend en charge Java.time

JPA 2.2 prend désormais en charge LocalDate, LocalTime, LocalDateTime, OffsetTime et OffsetDateTime.

<dependency>
  <groupId>javax.persistence</groupId>
  <artifactId>javax.persistence-api</artifactId>
  <version>2.2</version>
</dependency>

Hibernate 5.2 ou EclipseLink 2.7 peut être utilisé pour la mise en œuvre de JPA 2.2.

Hibernate 5 prend en charge davantage de types Java que JPA 2.2 tels que Duration, Instant et ZonedDateTime.

Plus d'informations: 

10
TheKojuEffect

J'utilise Java 8, EclipseLink (JPA 2.1), PostgreSQL 9.3 et le pilote PostgreSQL -Postgresql-9.2-1002.jdbc4.jar dans mon projet et je peux utiliser des variables LocalDateTime à partir de la nouvelle API sans problème, sauf le type de données de la colonne est bytea dans la base de données, donc vous ne pouvez le lire que depuis une application Java autant que je sache. Vous pouvez utiliser AttributeConverter pour convertir les nouvelles classes en Java.sql.Date Je trouve ce code dans Java.net

@Converter(autoApply = true)
public class LocalDatePersistenceConverter implements
AttributeConverter {
@Override
public Java.sql.Date convertToDatabaseColumn(LocalDate entityValue) {
    return Java.sql.Date.valueOf(entityValue);
}

@Override
public LocalDate convertToEntityAttribute(Java.sql.Date databaseValue) {
    return databaseValue.toLocalDate();
}
9
Ismael_Diaz

org.jadira.usertype peut être utilisé pour conserver l'API JSR 310 Date and Time.

Découvrez ce exemple de projet

De l'exemple de projet,

@MappedSuperclass
public class AbstractEntity {

    @Id @GeneratedValue Long id;

    @CreatedDate//
    @Type(type = "org.jadira.usertype.dateandtime.threeten.PersistentZonedDateTime")//
    ZonedDateTime createdDate;

    @LastModifiedDate//
    @Type(type = "org.jadira.usertype.dateandtime.threeten.PersistentZonedDateTime")//
    ZonedDateTime modifiedDate;
}
8
TheKojuEffect

Je sais que c’est une vieille question mais j’ai pensé à une solution alternative qui pourrait être utile.

Au lieu d'essayer de mapper les nouvelles classes Java.time. * Sur une base de données existante, vous pouvez utiliser @Transient:

@Entity
public class Person {
    private Long id;        
    private Timestamp createdTimestamp;

    @Id
    @GeneratedValue
    public Long getId() { return id; }

    private Timestamp getCreatedTimestamp() {
        return createdTime;
    }

    private void setCreatedTimestamp(final Timestamp ts) {
        this.createdTimestamp = ts;
    }

    @Transient
    public LocalDateTime getCreatedDateTime() {
        return createdTime.getLocalDateTime();
    }

    public void setCreatedDateTime(final LocalDateTime dt) {
        this.createdTime = Timestamp.valueOf(dt);
    }
}

Vous travaillez avec les méthodes getter/setter publiques qui utilisent les nouvelles classes date/heure de Java 8, mais en coulisse, les méthodes getter/setters utilisent les anciennes classes date/heure. Lorsque vous persistez dans l'entité, la propriété héritée date/heure sera conservée, mais pas la nouvelle propriété Java 8 puisqu'elle est annotée avec @Transient.

3
Jin Kim

Pour le typeTIMESTAMPvous pouvez utiliser ce convertisseur:

@Converter(autoApply = true)
public class LocalDateTimeAttributeConverter implements AttributeConverter<LocalDateTime, Timestamp> {

    @Override
    public Timestamp convertToDatabaseColumn(LocalDateTime datetime) {
        return datetime == null ? null : Timestamp.valueOf(datetime);
    }

    @Override
    public LocalDateTime convertToEntityAttribute(Timestamp timestamp) {
        return timestamp == null ? null : timestamp.toLocalDateTime();
    }

}

Pour le typeDATEvous pouvez utiliser ce convertisseur:

@Converter(autoApply = true)
public class LocalDateAttributeConverter implements AttributeConverter<LocalDate, Date> {

    @Override
    public Date convertToDatabaseColumn(LocalDate date) {
        return date == null ? null : Date.valueOf(date);
    }

    @Override
    public LocalDate convertToEntityAttribute(Date date) {
        return date == null ? null : date.toLocalDate();
    }

}

Pour le typeTIMEvous pouvez utiliser ce convertisseur:

@Converter(autoApply = true)
public class LocalTimeAttributeConverter implements AttributeConverter<LocalTime, Time> {

    @Override
    public Time convertToDatabaseColumn(LocalTime time) {
        return time == null ? null : Time.valueOf(time);
    }

    @Override
    public LocalTime convertToEntityAttribute(Time time) {
        return time == null ? null : time.toLocalTime();
    }

}
1
Paco

Il y a beaucoup d’approche à faire, cela dépend également de votre travail de cadre: Si votre travail de cadre a sur le terrain un convertisseur tel que le ressort, procédez comme suit: 1-.

@DateTimeFormat(pattern = "dd.MM.yyyy - HH:mm")
private Long createdDate;

ici, je me sers du format Epoch existant https://www.epochconverter.com/ Le format Epoch est très flexible et accepté

2- L’autre méthode consiste à utiliser jpa @PostLoad @PreUpdate @PrePersist

@PostLoad
      public void convert() {
        this.jva8Date= LocalDate.now().plusDays(1);
      }

ou utilisez temp un tel 

@Transient
public LocalDateTime getCreatedDateTime() {
    return createdTime.getLocalDateTime();
}
0
Ali.Mojtehedy