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();
}
}
Related
Error in request.getProductexpirationdate() since its not "Date" in proto thats specified as "timestamp".
Entity class has a "Date" but proto has no "Date" only "timestamp" so its not compatible.
How do i convert timestamp to date to make it compatible and sending data format as Date?
// EntityTest.class
#Data
#NoArgsConstructor
#AllArgsConstructor
public class ProductEntity {
private Integer purchase_item;
private String productname;
private String productbrand;
private Double productprice;
private String productdescription;
private Integer productquantity;
private Date productexpirationdate;
}
//GRPC Service
//Error in request.getProductexpirationdate() since its not "Date"
#GrpcService
public class ProductGRPCserver extends ProductServiceImplBase{
#Autowired
private ProductServiceImpl productServiceImpl;
#Autowired
private ProductDAO productDAO;
#Override
public void insert(Product request, StreamObserver<APIResponse> responseObserver) {
ProductEntity productEntity = new ProductEntity();
productEntity.setPurchase_item(request.getPurchaseItem());
productEntity.setProductname(request.getProductname());
productEntity.setProductbrand(request.getProductbrand());
productEntity.setProductprice(request.getProductprice());
productEntity.setProductdescription(request.getProductdescription());
productEntity.setProductquantity(request.getProductquantity());
productEntity.setProductexpirationdate(request.getProductexpirationdate());
productServiceImpl.saveDataFromDTO(productEntity);
APIResponse.Builder responce = APIResponse.newBuilder();
responce.setResponseCode(0).setResponsemessage("Succefull added to database " +productEntity);
responseObserver.onNext(responce.build());
responseObserver.onCompleted();
}
Assuming you are referring to google.protobuf.Timestamp, the easiest way to convert is with the com.google.protobuf.util.Timestamps utility:
Timestamp timestamp = Timestamp.fromMillis(date.getTime());
Timestamp stores the date as seconds and nanoseconds since 1970 whereas Date stores milliseconds since 1970. If you consult the google.protobuf.Timestamp documentation, it mentions how to do this manually conversion:
// The example used currentTimeMillis(), but let's use Date instead.
// long millis = System.currentTimeMillis();
long millis = date.getTime();
Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000)
.setNanos((int) ((millis % 1000) * 1000000)).build();
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.
I am using JPA with my Java project, and the timestamp is not working very well : it only shows 2015-08-12 00:00:00.0 (the day is correct but the hour is not)
#Entity
public class Session implements Serializable {
..
#Temporal(TemporalType.DATE)
private Date timestamp;
..
public Session(String sessionId) {
super();
this.sessionId = sessionId;
this.timestamp = new Date();
}
public Session() {
super();
this.timestamp = new Date();
}
}
Do you know how to fix this?
You should use TemporalType.TIMESTAMP that will map the field to a java.sql.Timestamp, hence it will contain also time related info, not only regarding date. In comparison, the type you used, TemporalType.DATE are mapped to java.sql.Date, class containing information like day, month year.
So, your code will transform in:
#Entity
public class Session implements Serializable {
..
#Temporal(TemporalType.TIMESTAMP)
private Date timestamp;
..
public Session(String sessionId) {
this.sessionId = sessionId;
this.timestamp = new Date();
}
public Session() {
this.timestamp = new Date();
}
}
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>
I have to convert the incoming parameter value to Repository interface into desired format, is it possible to do it. My Domain Class,
#DynamoDBTable(tableName = "test")
public class Test implements Serializable{
#Id
private String id;
private String name;
private String date;
#DynamoDBHashKey(attributeName = "id")
#DynamoDBAutoGeneratedKey
public String getId() {
return id;
}
#DynamoDBAttribute(attributeName = "name")
public String getName() {
return name;
}
#DynamoDBAttribute(attributeName = "date")
#JsonSerialize(using = StringDateSerializer.class)
public String getDate() {
return date;
}
public void setId(String id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
#JsonDeserialize(using = StringDateDeserializer.class)
public void setDate(String date) {
this.date = date;
}
}
And my repository interface,
#EnableScan
#RestResource(path="test", rel="test")
public interface TestRepository extends PagingAndSortingRepository<Test, String>{
#RestResource(path="testsearch", rel="test")
public Page<Test> findByNameAndDateLessThan(#Param("name") String name, #Param("date") String date, Pageable pageable);
}
Here I have to convert the incoming date String to time using getTime() method of Java. Is it possible to achieve this without using controller and am not interested in sending from client side because timezone problem may occur.
My Convertors:
public class StringDateSerializer extends JsonSerializer<String> {
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
#Override
public void serialize(String time, JsonGenerator gen,
SerializerProvider provider) throws IOException,
JsonProcessingException {
Date date = new Date(Long.parseLong(time));
String formattedDate = dateFormat.format(date);
gen.writeString(formattedDate);
}
}
public class StringDateDeserializer extends JsonDeserializer<String> {
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
#Override
public String deserialize(JsonParser parser, DeserializationContext context)
throws IOException, JsonProcessingException {
String dateReceived = parser.getText();
Date date = null;
try {
date = dateFormat.parse(dateReceived);
} catch (ParseException e) {
e.printStackTrace();
}
return String.valueOf(date.getTime());
}
}
Here I have to use, GET /test/search/test?name=xx&date=14-06-2014. I need to get all the names with date less than 14-06-2014 and left the datas with or after 14-06-2014.
While POST and GET, I have converted the incoming and outgoing string using JsonSerialize and JsonDeserialize annotations but if I want to fetch any data using finder method its not converting as I thought.
For example, If I save {"name": "Test", "date": "08-10-2014"}, in DB it will be saved by its equivalent time and If I want to search it using 08-10-2014 not the time constant. I am new to springs and I cant find a way for it. Thanks in advance.
What's the reason you use String as the type for the date in the first place. That's quite suboptimal (to phrase it politely) API design.
Spring Data REST support the usage of #DateTimeFormat on query method parameters to turn the String base representation you get from the HTTP request into a Date. So your repository interface might look something like this:
public interface TestRepository extends PagingAndSortingRepository<Test, String>{
public Page<Test> findByNameAndDate(#Param("name") String name,
#Param("date") #DateTimeFormat(iso = ISO.DATE) Date date, Pageable pageable);
}
This will cause Strings like 2014-06-08 to be turned into the appropriate Date.
If I'm understanding your issue correctly, there are two areas of concern - how Spring-Data-Rest handles date mapping, and how Spring-Data-DynamoDB handles date mapping.
With regard to Spring-Data-DynamoDB:
DynamoDB stores dates as Strings, so if you have a date attribute as part of your date model you can either represent them as Strings in your data model ( as I think you are doing currently ), or you can represent them as Dates, and configure Spring-Data-DynamoDB so that it maps the Dates to Strings. This can be done using Custom Marshallers from amazon-aws-sdk, and support has been added to handle this in the Spring Data DynamoDB module.
You can read about marshallers here : http://java.awsblog.com/post/Tx1K7U34AOZBLJ2/Using-Custom-Marshallers-to-Store-Complex-Objects-in-Amazon-DynamoDB
Note that this marshalling is separate from any mapping that you may be requiring Spring-Data-Rest to perform from JSON to objects - for this you will still need the #DateTimeFormat annotation.
If you want to represent the date as a java.util.Date in your data model, simply annotate the getter for the attribute in your domain class with #DynamoDBMarshalling, and pass in the class of marshaller you wish to use, eg:
#DynamoDBRangeKey(attributeName = "ReplyDateTime")
#DynamoDBMarshalling(marshallerClass=DefaultDynamoDBDateMarshaller.class)
public Date getReplyDateTime() {
...
DefaultDynamoDBDateMarshaller here is a support class from Spring-Data-DynamoDB, but you can implement your own for custom date/string mapping.
With this in place, you can now change your repository finder methods so they expect Date parameters rather than Strings:
public Page<Reply> findByReplyDateTimeAfter(Date replyDateTime,Pageable pageable);
Hope this helps,
Cheers,
Michael