How to persist LocalDate with JPA?
Solution 1
JPA 2.2 supports LocalDate
, so no converter is needed.
Hibernate also supports it as of 5.3 version.
Check out this article for more details.
Solution 2
With JPA 2.2, you no longer need to use converter it added support for the mapping of the following java.time types:
java.time.LocalDate
java.time.LocalTime
java.time.LocalDateTime
java.time.OffsetTime
java.time.OffsetDateTime
@Column(columnDefinition = "DATE")
private LocalDate date;
@Column(columnDefinition = "TIMESTAMP")
private LocalDateTime dateTime;
@Column(columnDefinition = "TIME")
private LocalTime localTime;
Solution 3
Hibernate 5 supports java 8, so you can add this to your pom.xml:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-java8</artifactId>
<version>5.1.0.Final</version>
</dependency>
This gives you mapping for LocalDate
and LocalDateTime
out of box.
Solution 4
JPA 2.2 added support for mapping Java 8 Date/Time API, like LocalDate
, LocalTime
, LocalDateTime
, OffsetDateTime
or OffsetTime
.
So, let's assume we have the following entity:
@Entity(name = "UserAccount")
@Table(name = "user_account")
public class UserAccount {
@Id
private Long id;
@Column(name = "first_name", length = 50)
private String firstName;
@Column(name = "last_name", length = 50)
private String lastName;
@Column(name = "subscribed_on")
private LocalDate subscribedOn;
//Getters and setters omitted for brevity
}
Notice that the subscribedOn
attribute is a LocalDate
Java object.
When persisting the UserAccount
:
UserAccount user = new UserAccount()
.setId(1L)
.setFirstName("Vlad")
.setLastName("Mihalcea")
.setSubscribedOn(
LocalDate.of(
2013, 9, 29
)
);
entityManager.persist(user);
Hibernate generates the proper SQL INSERT statement:
INSERT INTO user_account (
first_name,
last_name,
subscribed_on,
id
)
VALUES (
'Vlad',
'Mihalcea',
'2013-09-29',
1
)
When fetching the UserAccount
entity, we can see that the LocalDate
is properly fetched from the database:
UserAccount userAccount = entityManager.find(
UserAccount.class, 1L
);
assertEquals(
LocalDate.of(
2013, 9, 29
),
userAccount.getSubscribedOn()
);
Solution 5
I think you could write your own Converter, please check an answer: Spring Data JPA - Conversion failed when converting date and/or time from character string
Royce
Updated on January 09, 2021Comments
-
Royce over 3 years
I want to store Date without time into my database. So, I choose to use
LocalDate
type.As mentioned in this article, I use a JPA converter to convert
LocalDate
toDate
.However, I have some troubles when I want to persist my entity (with POST and PUT requests).
Error
2019-02-23 11:26:30.254 WARN 2720 --- [-auto-1-exec-10] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Expected array or string.; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Expected array or string. at [Source: (PushbackInputStream); line: 1, column: 104] (through reference chain: ...entity.MyObject["startdate"])] org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class org.springframework.http.ResponseEntity]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `org.springframework.http.ResponseEntity` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator) at [Source: (PushbackInputStream); line: 1, column: 2]
Code
Converter
package ...entity; import javax.persistence.AttributeConverter; import javax.persistence.Converter; import java.time.LocalDate; import java.sql.Date; @Converter(autoApply = true) public class LocalDateAttributeConverter implements AttributeConverter<LocalDate, Date> { @Override public Date convertToDatabaseColumn(LocalDate locDate) { return (locDate == null ? null : Date.valueOf(locDate)); } @Override public LocalDate convertToEntityAttribute(Date sqlDate) { return (sqlDate == null ? null : sqlDate.toLocalDate()); } }
Entity
package ...entity; import org.hibernate.annotations.ColumnDefault; import javax.persistence.*; import java.time.LocalDate; import java.util.HashSet; import java.util.Set; @Entity public class MyObject { @Id private String id; private LocalDate startdate; private LocalDate enddate; public MyObject() {} public MyObject(LocalDate enddate) { this.startdate = LocalDate.now(); this.enddate = enddate; } ... }
"Main"
private DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); MyObject myobject = new MyObject(LocalDate.parse("2019-03-01", formatter));
Thanks for help.
EDIT 1 : Print of MyObject
HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); HttpEntity<String> entity = new HttpEntity<>(this.toJsonString(myObject), headers); System.out.println(entity.toString()); // <{"id":"ba6649e4-6e65-4f54-8f1a-f8fc7143b05a","startdate":{"year":2019,"month":"FEBRUARY","dayOfMonth":23,"dayOfWeek":"SATURDAY","era":"CE","dayOfYear":54,"leapYear":false,"monthValue":2,"chronology":{"id":"ISO","calendarType":"iso8601"}},"enddate":{"year":2019,"month":"MARCH","dayOfMonth":1,"dayOfWeek":"FRIDAY","era":"CE","dayOfYear":60,"leapYear":false,"monthValue":3,"chronology":{"id":"ISO","calendarType":"iso8601"}}},[Content-Type:"application/json"]>
-
user666 about 3 yearsif i have LocalDate optional and i send it as null, oracle returns: expected date got binary, this does not happen if i am using java.util.Date. How can I solve it with jpa?
-
lostiniceland over 2 yearsWhat is Hibernate using when mapping LocalDate? I need to adjust the datein case of LocalDate.MAX to, for instance 31.12.9999. I am using an AttributeConverter<LocalDate, Date> and it works, but java.sql.Date is horrible when mapping LocalDate.MIN because I need to allow 01.01.0001 but I cannot set java.sql.Date to anything lower than that.