I'm using Spring Boot 1.5.1 and getting an exception anytime I hit my API when there is a LocalDateTime field in my Entity class.
The MySQL dt column is TIMESTAMP
Is JPA not able to natively deserialize LocalDateTime?
Console output when performing GET request
2017-03-02 22:00:18.797 ERROR 13736 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.orm.jpa.JpaSystemException: could not deserialize; nested exception is org.hibernate.type.SerializationException: could not deserialize] with root cause
java.io.StreamCorruptedException: invalid stream header: 20323031
Reservation.class
package com.example.springboot.reservation;
import java.time.LocalDateTime;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
// Model class
@Entity
@Table(name="reservation")
public class Reservation {
@Id
private Long id;
@Column
private LocalDateTime dt;
@Column(name="user_id")
private Long userId;
// Hibernate will convert camel case column names to snake case!!!
// Don't use camelcase columns in DB
@Column(name="party_size")
private int partySize;
public Reservation() {}
public Reservation(Long id, Long userId, int partySize) {
this.id = id;
this.userId = userId;
this.partySize = partySize;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public LocalDateTime getDt() {
return dt;
}
public void setDt(LocalDateTime dt) {
this.dt = dt;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public int getPartySize() {
return partySize;
}
public void setPartySize(int partySize) {
this.partySize = partySize;
}
}
pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.1.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<java.version>1.8</java.version>
</properties>
@Converter
public class LocalDateTimeConverter implements AttributeConverter<java.time.LocalDateTime, java.sql.Timestamp> {
@Override
public java.sql.Timestamp convertToDatabaseColumn(java.time.LocalDateTime entityValue) {
return entityValue == null ? null : java.sql.Timestamp.valueOf(entityValue)
}
@Override
public java.time.LocalDateTime convertToEntityAttribute(java.sql.Timestamp dbValue) {
return dbValue == null ? null : dbValue.toLocalDateTime();
}
}
Make sure that this converter class is added to the package scanned by hibernate. Add this converter to the column declaration
@Column
@Convert(converter = LocalDateTimeConverter.class)
private LocalDateTime dt;
If you are not using JPA 2.0, This answer would help you use @Temporal
annotation for LocalDateTime.
You don't need a converter if you use the newer hibernate-java8 which has LocalDateTime support.
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-java8</artifactId>
<version>${hibernate.version}</version>
</dependency>
You can write converter as described below:
@Converter(autoApply = true)
public class MyLocalDateConverter implements AttributeConverter<java.time.LocalDate, java.sql.Date> {
@Override
public java.sql.Date convertToDatabaseColumn(java.time.LocalDate attribute) {
return attribute == null ? null : java.sql.Date.valueOf(attribute);
}
@Override
public java.time.LocalDate convertToEntityAttribute(java.sql.Date dbData) {
return dbData == null ? null : dbData.toLocalDate();
}
}
You can find some already baked converters in spring package:
org.springframework.data.jpa.convert.threeten.Jsr310JpaConverters
JDocs:
JPA 2.1 converters to turn JSR-310 types into legacy Dates. To activate these converters make sure your persistence provider detects them by including this class in the list of mapped classes. In Spring environments, you can simply register the package of this class (ie org.springframework.data.jpa.convert.threeten) as package to be scanned on eg the LocalContainerEntityManagerFactoryBean.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.