I am working with PostgreSQL database and timestamp columns have class java.sql.Timestamp. Even if this class extends java.util.Date, when I edit PopupDateFiels, I obtain error
Unable to convert value of type java.util.Date to model type class java.sql.Timestamp. No converter is set and the types are not compatible.
Default converter factory is unable to work properly. I tried to write
dateField.setConverter(new DateToSqlDateConverter());
or
dateField.setConverter(StringToDateConverter.class);
with the same result.
By clicking on a day in calendar, I can see valid date and time in european format "23.10.2014 13.44", but commit failed with similar messages on console:
Caused by: com.vaadin.data.util.converter.Converter$ConversionException: Could not convert value to Timestamp
at com.vaadin.ui.AbstractField.convertToModel(AbstractField.java:725)
at com.vaadin.ui.AbstractField.getConvertedValue(AbstractField.java:811)
at com.vaadin.ui.AbstractField.commit(AbstractField.java:247)
... 42 more
Caused by: com.vaadin.data.util.converter.Converter$ConversionException: Unable to convert value of type java.util.Date to model type class java.sql.Timestamp. No converter is set and the types are not compatible.
at com.vaadin.data.util.converter.ConverterUtil.convertToModel(ConverterUtil.java:181)
at com.vaadin.ui.AbstractField.convertToModel(AbstractField.java:745)
... 45 more
Where can I get proper converter? Thanks for advice.
Do Not Think Of
java.sql.Timestamp
As Subclass Ofjava.util.Date
While
java.sql.Timestamp
does technically inherit fromjava.util.Date
, the last paragraph of the class doc states that you should not consider it so, that you should ignore that fact.In other words, this class structure is a clumsy hack. The date-time classes in early Java were rushed, and were not well thought-out.
One problem in converting is that java.sql.Timestamp has nanosecond resolution but java.util.Date has only milliseconds, so data will be lost.
Beware that Vaadin makes this mistake with a SQLContainer backing a Grid (and presumably a Table). The java.sql.Timestamp columns in the SQLContainer are treated as java.util.Date (superclass) thereby losing data if microseconds or nanoseconds were involved. (See my converter implementation below as workaround.)
java.time
The new java.time package in Java 8 and later is a re-think of those old classes, a do-over from scratch. These new classes are inspired by Joda-Time, defined by JSR 310, and extended by the ThreeTen-Extra project.
The java.time classes are built for nanosecond resolution. So no data loss when converting between java.time.Instant and java.sql.Timestamp.
Both the old and new date-time classes have methods for converting back and forth between old and new. Notice the
java.sql.Timestamp::toInstant
andTimestamp.from( instant )
methods called below.Converter for String of java.time.Instant ↔ java.sql.Timestamp
This example may or may not help answer the Question. I am converting java.sql.Timestamp data for presentation as a String of java.time.Instant.
Besides textual format, remember there is one big difference between my converter and the default one: No data loss! (see discussion above) This example screenshot happens to not have any fractional seconds. But if it did have microseconds or nanoseconds, that data would be retained and displayed as need be.
Here is some code doing a String representation of an
Instant
converted from a java.sql.Timestamp. In other words:This code is modified from the source code of the
com.vaadin.data.util.converter.StringToDateConverter
class bundled with Vaadin 7.This code is working for me in displaying a
SQLContainer
object’s java.sql.Timestamp columns in Vaadin 7.5.2 in aGrid
. I've not yet triedTable
but should work there too.While working for me, this code may need some cleanup. In particular, (a) the comments may be wrong, and (b) I have calls to SLF4J logging that you may need to alter/remove.
The default ISO 8601 format is a bit hard to read for humans, so I am working an alternatives for changing the format and for adjusting the time zone.
To use this class, you must call
setConverter
on aGrid.Column
object. Or configure aConverterFactory
as described in this wiki page.I recommend this way:
with this converter: