persist java LocalDate in MySQL - java

I'm writing a java client application using: SE 8, MySQL 5.6 (Connector/J 5.1), JPA 2.1. when I try to persist an entity with an ID (int Auto-increment), date (LocalDate). it throw an Exception says:
Internal Exception: com.mysql.jdbc.MysqlDataTruncation: Data truncation: Incorrect date value: '\xAC\xED\x00\x05sr\x00\x0Djava.time.Ser\x95]\x84\xBA\x1B"H\xB2\x0C\x00\x00xpw\x07\x03\x00\x00\x07\xDF\x03\x06x' for column 'date' at row 1
does MySQL (I mean The Connector) do not support the new Date and Time API or What. if so What Can I do??
#Entity
#Table(schema="app")
public class Run implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int id; //number of connections
private LocalDate date;

Registering the custom converter should help you solve your issue
#Converter(autoApply = true)
public class LocalDatePersistenceConverter implements
AttributeConverter<LocalDate, Date> {
#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();
}
}
more about converting the LocalDate info and some more about using the converters

AttributeConverter is also generic:
#Converter(autoApply = true)
public class LocalDatePersistenceConverter implements
AttributeConverter<LocalDate, Date> {
#Override
public Date convertToDatabaseColumn(LocalDate entityValue) {
return java.sql.Date.valueOf(entityValue);
}
#Override
public LocalDate convertToEntityAttribute(Date databaseValue) {
return databaseValue.toLocalDate();
}
}

If working with hibernate I just found here that also one can take advantage of Java 8 support shipped in a separate jar file called hibernate-java8.jar. So basically you can just add something like this in your pom and be ready to go:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-java8</artifactId>
</dependency>

Related

Is there any way to map MySql TIMESTAMP to java.lang.Long?

So I have this object saved to the database with one property being dateCreated which is, of course, saved as MySQL timestamp. But while sending the data to the client, I want to be in milliseconds. Right now, I've mapped it to the Date object and converting it to milliseconds further. But I thought, what if I could map my POJO in such a way that it retrieves values in milliseconds. Here is what I've tried.
OmsJob:
#Entity
#EntityListeners(PreventAnyUpdate.class)
#ConfigurationProperties("omsjob")
#Table(name = "OMSJob")
public class OmsJob {
#Id
#NotNull
#Column(name = "jobId")
private String id;
#NotNull
private Long dateCreated; // If I map this property to Date, it works fine
}
I thought I'll add a custom converter that'll convert java.util.Date or java.sql.Date to milliseconds. But it isn't working:
#Component
#ConfigurationPropertiesBinding
public class DateConverter implements Converter<Date, Long> {
#Override
public Long convert(Date date) {
return date.getTime();
}
}
The error I am getting is pretty obvious but is there any way to achieve what I am trying to?
ERROR 229770 --- [ main] o.h.engine.jdbc.spi.SqlExceptionHelper : Unsupported conversion from TIMESTAMP to java.lang.Long
An attribute won't know about its converter until you declare it. Do it as follows:
#NotNull
#Convert (converter = DateConverter.class)
private Long dateCreated;
Also, change the converter as follows:
public class DateConverter implements AttributeConverter<Date, Long> {
#Override
public Date convertToDatabaseColumn(Long millis) {
retrun new Date(millis);
}
#Override
public Long convertToEntityAttribute(Date date) {
return date.getTime();
}
}

Migration from org.joda.time.Interval in Spring Boot

I used to apply org.joda.time.Interval to represent a time interval with fixed start and end times (different from a duration which is independent from specific times) to exchange via REST and store energy schedules in a Spring Boot server application (2.2.2.RELEASE).
I tried different ways to store a org.joda.time.Interval field of an object via JPA/Hibernate:
jadira (7.0.0.CR1) with annotation above the field definition (#Type(type = "org.jadira.usertype.dateandtime.joda.PersistentInterval"))
jadira (7.0.0.CR1) with property spring.jpa.properties.jadira.usertype.autoRegisterUserTypes=true set
However, I always get
#OneToOne or #ManyToOne on de.iwes.enavi.cim.schedule51.Schedule_MarketDocument.matching_Time_Period_timeInterval references an unknown entity: org.joda.time.Interval
Questions:
Is there a way to get hibernate working with org.joda.time.Interval?
What is the preferred solution to migrate from org.joda.time.Interval as java.time does not have a similar interval class?
I ended up writing a custom class:
#Entity
public class FInterval {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
#Column
private long startMillis;
#Column
private long endMillis;
public FInterval() {
}
public long getStartMillis() {
return startMillis;
}
public void setStartMillis(long start) {
this.startMillis = start;
}
public long getEndMillis() {
return endMillis;
}
public void setEndMillis(long end) {
this.endMillis = end;
}
public FInterval(Interval entity) {
this.startMillis = entity.getStartMillis();
this.endMillis = entity.getEndMillis();
}
public Interval getInterval() {
return new Interval(this.startMillis,this.endMillis);
}
}
and an attribute converter:
#Converter(autoApply = true)
public class IntervalAttributeConverter implements AttributeConverter<Interval, FInterval> {
#Override
public FInterval convertToDatabaseColumn(Interval attribute) {
return new FInterval(attribute);
}
#Override
public Interval convertToEntityAttribute(FInterval dbData) {
return dbData.getInterval();
}
}

Complex object mapping in Android

I'm dabbling in the Android Room persistence library, and I have this object that is a result of a JSON parse:
#Entity
public class Cluster {
#PrimaryKey
private int id;
private boolean is_up;
private ClusterStatus status;
private ClusterLoad load;
private List<Server> servers = null;
private UserQueries user_queries;
}
Example of a ClusterStatus Object (getters and setters omitted for brevity), to show that TypeConverter isn't helpful:
public class ClusterStatus {
private boolean isOnline;
private String name;
private int upTime;
}
Do I map all these inner Objects as separate Entities?
How do I map a List of Objects properly? (I've read the Doc but didn't get why the annotations go the way they go)
Maybe you can advise me some other ORM, that handles these relations better?
Use TypeConverters
Make a TypeConverter class like this :
(This example is for Date, you can similarly make for other Objects)
public class DateConverter {
#TypeConverter
public static Date toDate(Long timestamp) {
return timestamp == null ? null : new Date(timestamp);
}
#TypeConverter
public static Long toTimestamp(Date date) {
return date == null ? null : date.getTime();
}
}
Add TypeConverter in RoomDatabase class like this:
#Database(entities = {TaskEntry.class}, version = 1, exportSchema = false)
#TypeConverters(DateConverter.class)
public abstract class AppDatabase extends RoomDatabase
{
...
...
}
Official Documentation :
TypeConverter
TypeConverters

Date conversion for DAO unit tests

I am upgrading our application to a version of the framework that supports Java 8's Date/Time API. I've updated our entity models to reflect the correct type conversion (date -> LocalDate, timestamp -> LocalDateTime).
I'm now hitting an issue running my unit tests where the converters are attempting to cast java.sql.Date as java.sql.Timestamp. This is confusing because Timestamp shouldn't be used for these entities. The testing SQL script uses TO_DATE() to set the dates, like so:
INSERT INTO note (id, content, date, owner_id) VALUES (1, 'test content', TO_DATE('17/12/2017', 'DD/MM/YYYY'), 1);
And the exception returned is:
Caused by: java.lang.ClassCastException: java.sql.Timestamp cannot be cast to java.sql.Date
at com.<redacted>.model.jpa.LocalDateAttributeConverter.convertToEntityAttribute(LocalDateAttributeConverter.java:8)
at org.hibernate.metamodel.model.convert.internal.JpaAttributeConverterImpl.toDomainValue(JpaAttributeConverterImpl.java:45)
at org.hibernate.type.descriptor.converter.AttributeConverterSqlTypeDescriptorAdapter$2.doConversion(AttributeConverterSqlTypeDescriptorAdapter.java:140)
... 64 more
from a simple AttributeConverter<>:
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
import java.sql.Date;
import java.time.LocalDate;
#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());
}
}
I can understand it having an issue casting from Timestamp to Date but Timestamp shouldn't be involved at all here.
Entity for completeness:
#XmlRootElement
#Entity(name = "notes")
public class Note implements ModelObject {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne(optional = false)
#JoinColumn(name = "owner_id", referencedColumnName = "id")
private User user;
private String content;
private LocalDate date;
// getters/setters omitted for brevity
}
Not sure if this affects it, but I have also created AttributeConverters for LocalTime and LocalDateTime.
#Converter(autoApply = true)
public class LocalTimeAttributeConverter implements AttributeConverter<LocalTime, Time> {
#Override
public Time convertToDatabaseColumn(LocalTime localTime) {
return (localTime == null ? null : Time.valueOf(localTime));
}
#Override
public LocalTime convertToEntityAttribute(Time sqlTime) {
return (sqlTime == null ? null : sqlTime.toLocalTime());
}
}
#Converter(autoApply = true)
public class LocalDateTimeAttributeConverter implements AttributeConverter<LocalDateTime, Timestamp> {
#Override
public Timestamp convertToDatabaseColumn(LocalDateTime locDateTime) {
return (locDateTime == null ? null : Timestamp.valueOf(locDateTime));
}
#Override
public LocalDateTime convertToEntityAttribute(Timestamp sqlTimestamp) {
return (sqlTimestamp == null ? null : sqlTimestamp.toLocalDateTime());
}
}
Using Hibernate 5.3.0.Final and H2 1.4.197 with hibernate-java8 library.

Play framework 2 and automatically adding an add_date to an ebeans item

I have a small difficulty with ebeans.
I used to create items with the following code, populating the addDate:
#MappedSuperclass
public abstract class GenericModel extends Model {
#Id
protected Long id;
#UpdatedTimestamp
#Version
private Date lastUpdate;
#CreatedTimestamp
protected Date addDate;
public Long getId(){
return id;
}
public Date getLastUpdate(){
return lastUpdate;
}
public Date getAddDate(){
return addDate;
}
}
However, as I need to synchronise the data with an offline device, I changed it to:
#MappedSuperclass
public abstract class GenericModel extends Model {
#Id
protected Long id;
#UpdatedTimestamp
#Version
private Date lastUpdate;
protected Date addDate;
public Long getId(){
return id;
}
public Date getLastUpdate(){
return lastUpdate;
}
public Date getAddDate(){
return addDate;
}
#WhenCreated
private void addCreateTimestamp(){
if(this.addDate == null) this.addDate = new Date();
}
}
But this doesn't work, as there is an exception that the addDate cannot be null when inserting.
Is there another way of populating the addDate is not set (for the synchronisation I sometimes I need to set the addDate manually so it is the same as the master).
[EDIT:] this problem doesn't seem to show up on my development system with men db, but when deployed with MySql
#WhenCreated is just an alias for #CreatedTimestamp. What are you expecting putting this annotation before the addCreateTimestamp() method. This method is never executed in your case, so the addDate is never set.
Try this:
#MappedSuperclass
public abstract class GenericModel extends Model {
// ...
protected Date addDate;
// ...
#Override
public void save() {
addCreateTimestamp();
super.save();
}
private void addCreateTimestamp(){
if(this.addDate == null) this.addDate = new Date();
}
// ...

Categories

Resources