When i receive firestore DocumentSnapshot field(which is timestamp) with:
DocumentSnapshot snapshot = message.getPayload().getDocumentSnapshot();
Object o = snapshot.get("fieldName);
everything works fine and Object o is instantiated with real data Thu Jan 10 00:00:00 CET 2019
But when i try to receive the field as google.cloud.Timestamp:
DocumentSnapshot snapshot = message.getPayload().getDocumentSnapshot();
Timestamp ts = snapshot.getTimestamp("fieldName");
or Timestamp ts = (Timestamp) snapshot.get("fieldName");
it fails with error java.util.Date cannot be cast to com.google.cloud.Timestamp
Could someone clarify this behavior and how should i access ad retrieve google.cloud.Timestamp object from DocumentSnapshot? Im having this problem only with Timestamp object, every other type parses normally.
EDIT, adding more code:
Accessing firestore:
#Bean
public FirestoreGateway registerFirestoreGateway(FirestoreGatewayProperties properties) throws IOException {
Resource resource = new ClassPathResource(properties.getFirestoreConfiguration());
InputStream configuration = resource.getInputStream();
FirebaseOptions options = new FirebaseOptions.Builder()
.setCredentials(GoogleCredentials.fromStream(configuration))
.setDatabaseUrl(properties.getDatabaseUrl())
.build();
FirebaseApp.initializeApp(options);
return new FirestoreGateway(FirestoreClient.getFirestore());
}
Firestore snapshot listener:
#EventListener(ApplicationReadyEvent.class)
public void listenToRequestCommands() {
firestoreConnection.listCollections().forEach(collectionReference -> {
collectionReference
.document(properties.getFirestoreCommand())
.addSnapshotListener((snapshot, e) -> {
Object o = snapshot.get("timestamp");
Timestamp ts = (Timestamp) snapshot.get("timestamp");
}
);
});
}
Object o parses normally to right value, while Timestamp ts for the
same event throws "java.util.Date cannot be cast to
com.google.cloud.Timestamp"
Timestamp field definition in database:
You are getting the following error:
java.util.Date cannot be cast to com.google.cloud.Timestamp
Because in your database the timestamp property is of type Date and not Timestamp. There is no way in Java to cast an object of type Date to an object of type com.google.firebase.Timestamp because there is no inheritance relationship between them.
To solve this, you need to get that property as Date, using the following line of code:
Date timestamp = snapshot.getDate("timestamp");
Edit:
When you are setting a field to be of type timestamp, you are setting it as Timestamp, which is apart of another package. See, class Timestamp extends Date. So a timestamp object is-a Date, because it inherits from the Date class.
As a conclusion, the Timestamp class from the com.google.firebase package is different from the Timestamp class from the java.sql package, which in terms is different from the Timestamp class that exists within java.security package.
Edit2:
According to your comment, when using:
(java.util.Date) snapshot.get("timestamp");
It means that the object that is returned by snapshot.get("timestamp") is casted to Date, which basically is the same thing. With other words, you tell the compiler that whatever the object that is returned, consider it a Date object. And it works because the type of your property in the database is Date and not Firebase Timestamp.
Kotlin solution that work for me:
val timestamp: Date = document.getDate("timestamp") as Date
Related
My project is using Oracle database, and everything works just fine. For the purpose of testing I set up an H2 db. The following query now throws an error:
"SELECT * FROM ERESIS.ECH_HISFAB f WHERE f.FG_ETAT = 'A' AND TO_DATE(DT_INS) > '30-AUG-18' ORDER BY f.CD_MAT"
error:
Cannot parse "TIMESTAMP" constant "30-AUG-18"; SQL statement:
I can fix the error by setting up the string like TO_DATE('30-AUG-2018'), but changing the query kind of defeats the purpose since I already am sure the query works (but I need it to test the service). Is there any way to bypass this error without changing the query?
parsedatetime() should be able to convert string to TIMESTAMP, please try using -
"SELECT * FROM ERESIS.ECH_HISFAB f WHERE f.FG_ETAT = 'A' AND TO_DATE(DT_INS) > parsedatetime('30-AUG-2018', 'dd-MMM-yyyy') ORDER BY f.CD_MAT"
I had a similar issue with H2 (1.4.200), it has just one format for TO_DATE(input) method "DD MON YYYY".
After a debug I found that H2 uses an enum for date format when it's not provided as second parameter: org.h2.expression.function.ToDateParser.ConfigParam
TO_DATE("DD MON YYYY")
I did a solution to override it using reflection so that the sql code does not change.
In my unit test I created a utility method used to instantiate the workaround on #BeforeClass
private static boolean h2WorkaroundApplied = false; //utility to apply workaround just one time
protected static synchronized void applyH2ToOracleCompatibilityWorkaround() {
if (!h2WorkaroundApplied) {
fixH2ToDateFormat(); //apply to_date workaround
h2WorkaroundApplied = true; //disable future changes of same workaround
}
}
private static void fixH2ToDateFormat() {
try {
Class<?> classConfigParam = Arrays.stream(ToDateParser.class.getDeclaredClasses())
.filter(c -> "ConfigParam".equals(c.getSimpleName()))
.findFirst()
.orElseThrow(); //get the enum inner class
Object toDateEnumConstant = Arrays.stream(classConfigParam.getEnumConstants())
.filter(e -> "TO_DATE".equals(((Enum) e).name()))
.findFirst()
.orElseThrow(); //get the enum constant TO_DATE
Field defaultFormatStr = classConfigParam.getDeclaredField("defaultFormatStr"); //get the enum private field defaultFormatStr
defaultFormatStr.setAccessible(true);
defaultFormatStr.set(toDateEnumConstant, "YYYY-MM-DD"); //change with my date format used by production oracle DB.
} catch (Exception e) {
throw new UnsupportedOperationException(
"The current H2 version doesn't support this workaround. Tested with version 1.4.200", e);
}
}
I want to send this request
http://localhost:8080/{url}?start=2020-04-20&end=2020-04-24&status=success&status=failed
In Transaction model
private java.sql.Timestamp addedOn;
I am trying to create a dynamic query for multiple filters following this blog:
https://attacomsian.com/blog/spring-data-jpa-specifications
Specs.java file toPredicate method
if (criteria.getOperation().equals(SearchOperation.GREATER_THAN)) {
predicates.add(builder.greaterThan(
root.get(criteria.getKey()), criteria.getValue().toString()));
} else if (criteria.getOperation().equals(SearchOperation.LESS_THAN)) {
predicates.add(builder.lessThan(
root.get(criteria.getKey()), criteria.getValue().toString()));
}
Here is my Controller code
Timestamp start = new Timestamp(dateFormat.parse(request.getParameter("start")).getTime());
Timestamp end = new Timestamp(dateFormat.parse(request.getParameter("end")).getTime());
Specs txnSpecs = new Specs();
txnSpecs.add(new SearchCriteria("addedon", start, SearchOperation.GREATER_THAN_EQUAL));
txnSpecs.add(new SearchCriteria("addedon", end, SearchOperation.LESS_THAN_EQUAL));
txnSpecs.add(new SearchCriteria("status", Arrays.asList(request_params.get("status")), SearchOperation.IN));
List<Transaction> txnList = transactionRepository.findAll(txnSpecs);
return txnList;
But when I make request I get:
nested exception is java.lang.IllegalArgumentException: Parameter value [2020-04-20] did not match expected type [java.util.Date (n/a)]]
Do I need to convert the Date value before I send it as param for the SQL query? Or I need to use other types of Date?
Do I need to convert the Date value before I send it as param for the SQL query?
No, the opposite is true, you must keep it a Date but you convert it to a String by calling criteria.getValue().toString().
Check if your dateFormat are correct to pattern of your value: yyyy-MM-dd :
DateFormat dateFormat = new SimpleDateFormat ("yyyy-MM-dd");
I am getting the following error while persisting a LocalDate field [Using VARCHAR(20) type in column]:
Value too long for column "BIRTH_DATE VARCHAR(20)":"'aced00057372000d6a6176612e74696d652e536572955d84ba1b2248b20c00007870770703000007e2060c78' (88)";
The field definition is as follows:
#Column(name = "BIRTH_DATE")
private LocalDate date;
#Column(name = "BIRTH_TIME")
private LocalTime time;
I am using spring data starter (1.5.9.RELEASE). Which internally uses hibernate 5.0.12.
According to the blogpost https://www.thoughts-on-java.org/hibernate-5-date-and-time/
Hibernate 5, supports Java 8 features (DateTime API) out of the box. So, why this error is coming.
I have checked, and a valid LocalDate object is being created in run time. But the error is thrown while persisting. Here is the debug screenshot just before the call to save()
The error changes to the following, if I change column type to DATE:
java.lang.IllegalArgumentException: aced00057372000d6a6176612e74696d652e536572955d84ba1b2248b20c00007870770703000007e2060c78
at org.h2.util.DateTimeUtils.parseDateValue(DateTimeUtils.java:313) ~[h2-1.4.196.jar:1.4.196]
The string you’ve encountered is the hexadecimal representation of a serialized object, which can be verified easily:
ByteArrayInputStream is = new ByteArrayInputStream(new BigInteger(
"aced00057372000d6a6176612e74696d652e536572955d84ba1b2248b20c00007870770703000007e2060c78", 16)
.toByteArray());
is.read();
ObjectInputStream ois = new ObjectInputStream(is);
final Object obj = ois.readObject();
System.out.println(obj+" ("+obj.getClass().getName()+')');
2018-06-12 (java.time.LocalDate)
Of course, storing a LocalDate as such a blob is not a sign of a genuine DateTime API support, as that should be the last resort for storing a value. Either, there is no support or it has not been properly configured. In either case, you have to recheck the environment.
Can someone please tell me why the value of my field in the database which has a data type of datetime always store the value 1970-01-01 no matter what value I input? Here is the code
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "date_received")
private Date dateReceived = new Date();
and this is the code I use to insert
#PostMapping("/createJrf")
public ResponseEntity<String> createJrf(#Valid #RequestBody JobRequirement req) {
jrRepository.save(req);
return new ResponseEntity<>("Job Created", HttpStatus.CREATED);
}
Problem solved it was all in the format of my json in postman I was previously doing it as follows
"dateReceived": "20180302"
then I changed it to
"dateReceived": "2018-03-02"
#Temporal(javax.persistence.TemporalType.DATE)
private Date docDate;
public Date getDocDate() {
return docDate;
}
public void setDocDate(Date docDate) {
this.docDate = docDate;
}
but the error shows like this
Error setting expression 'docDate' with value '[Ljava.lang.String;#843f72'
ognl.MethodFailedException: Method "setDocDate" failed for object net.top.app.entity.document.Document#291a66 [java.lang.NoSuchMethodException: net.top.app.entity.document.Document_$$_javassist_4.setDocDate([Ljava.lang.String;)]
at ognl.OgnlRuntime.callAppropriateMethod(OgnlRuntime.java:1285)
at ognl.OgnlRuntime.setMethodValue(OgnlRuntime.java:1474)
Your code is trying to pass a String to setDocDate(). Change it so as to pass a Date.
As per the Error , setDocDate() is having Date field as input type.
You are setting the docDate in UI it self, try to convert the field to Date and set it to docDate