Why this piece of code is throwing classCastException - java

List<Object[]> arrayList = new ArrayList<Object[]>();
for(Object[] obj: arrayList)
{
// assuming at 0th location Timestamp value
Date dt = convertTimestampToDate((Timestamp)obj[0]) // Timestampvalue , '2013-09-11 00:00:0' throwing classCastException at this line
}
public static java.sql.Date convertTimestampToDate(java.sql.Timestamp timestamp) {
if(isNull(timestamp))
return null;
long milliseconds = timestamp.getTime() + (timestamp.getNanos() / 1000000);
return new java.sql.Date(milliseconds);
}
Exception thrown is
You cannot cast java.lang.String to Timestamp
Here, I am assuming obj[0] is an object type and casting it to Timestamp
Any Ideas will be appreciable.

The exception is pretty self explanatory. In Java, everything is an Object (with the exception of primitives, but that's another subject). So, even though you've got an array of Objects, that doesn't mean you can arbitrarily cast those Objects to anything you want.
Date dt = convertTimestampToDate((Timestamp)obj[0])
obj[0] is clearly a String when you attempt that cast, and as such you will need to use SimpleDateFormat or similar to parse that String. You cannot cast a String to a Timestamp for the simple reason that Java doesn't (and can't) know how to do that.

You should convert the String object to Timestamp by using the Timestamp#valueOf(String s) method.
Change
Date dt = convertTimestampToDate((Timestamp)obj[0]) ;
to
Date dt = convertTimestampToDate(Timestamp.valueOf(obj[0].toString()));

Related

Is this additional check for parsing a string to LocalDate object necessary?

I was writing some tests for some legacy code that validates a user's date of birth. I encounter the following method in the class. My doubt is that whether the if statement in the try block is necessary. From my understanding, if the parse function returns a LocalDate object successfully, then date.toString() should always equal to the input dobstr, and there's no need to do an additional check. Am I missing anything? I could not think of any case that we need this extra check. Please help. Thanks!
private LocalDate format(String dobStr) throws Exception {
LocalDate date = null;
try {
date = LocalDate.parse(dobStr, DateTimeFormatter.ISO_DATE);
if (!dobStr.equals(date.toString())) {
throw new DateTimeParseException("some message");
}
}
catch (DateTimeParseException ex) {
throw ex;
}
return date;
}
this is what I found in the source code for DateTimeFormatter.ISO_DATE
public static final DateTimeFormatter ISO_DATE;
static {
ISO_DATE = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.append(ISO_LOCAL_DATE)
.optionalStart()
.appendOffsetId()
.toFormatter(ResolverStyle.STRICT, IsoChronology.INSTANCE);
}
The only reason that I could see for doing a toString() check would be to avoid lenient issue: the parser may be lenient and try to interpret wrong values (for example: 2020-12-32 could be interpreted as 2021-01-01).
DateFormat allows the parser to be lenient
The same behaviour is offered by DateTimeFormatter and the default value is ResolverStyle.SMART.
If you want to remove it, you should check if DateTimeFormatter.ISO_DATE is ResolverStyle.STRICT by default or not. Assuming it is not STRICT by default, your code could be:
private LocalDate format(String dobStr) throws Exception {
return LocalDate.parse(dobStr, DateTimeFormatter.ISO_DATE.withResolverStyle(ResolverStyle.STRICT));
}
TL;DR: The check makes a difference
If the string contains an unwanted offset ID, you will still be able to parse it using DateTimeFormatter.ISO_DATE. But since a LocalDate cannot have an offset (this is what local in the name means), the result of toString() will never have that offset ID, so the strings will not be equal.
DateTimeFormatter.ISO_DATE accepts an optional offset ID after the date. So if you are parsing 2020-08-12z or 2020-08-12+01:02:03, the custom exception would be thrown. Except for a detail: DateTimeParseException hasn’t got a constructor that matches a single string argument, so the code doesn’t compile. I reckon that this comes from sloppy copy-paste from the original code.
To demonstrate:
String dobStr = "2020-08-12+01:02:03";
LocalDate date = LocalDate.parse(dobStr, DateTimeFormatter.ISO_DATE);
String asStringAgain = date.toString();
System.out.format("Original string: %s; result of toString(): %s; equal? %s%n",
dobStr, asStringAgain, dobStr.equals(asStringAgain));
Output is:
Original string: 2020-08-12+01:02:03; result of toString():
2020-08-12; equal? false
How to obviate the check
Unless you require a custom exception in the case of an unwanted offset, the method may be written much more simply:
private LocalDate format(String dobStr) throws Exception {
return LocalDate.parse(dobStr, DateTimeFormatter.ISO_LOCAL_DATE);
}
DateTimeFormatter.ISO_LOCAL_DATE does not accept any offset in the string. And it is strict just like DateTimeFormatter.ISO_DATE, so we know that toString() would create the same string again.
Furthermore you may declare the method static, and you may leave out throws Exception since DateTimeParseException is an unchecked exception.
Link
Documentation of DateTimeFormatter.ISO_DATE

Converting java.lang.double to org.joda.time.Instant

I have looked around a lot. I am very new to Java, and I am trying to cast a Double into an Instant. The use case is for the Google Dataflow Java SDK. The Double is a UNIX timestamp from a file I read using TextIO. When I System.out.println(row.get("timestamp")) I indeed get UNIX timestamps. When I do System.out.println(row.get("timestamp").getClass().getName()), then I get java.lang.double. what I have is as follows:
static class ExtractTimestamp extends DoFn<TableRow, TableRow> {
#Override
public void processElement(ProcessContext c) {
TableRow row = c.element();
Instant timestamp = (Instant) row.get("timestamp");
c.outputWithTimestamp(row, timestamp);
}
}
The error I am getting is:
java.lang.Double cannot be cast to org.joda.time.Instant
The problem is that I want to cast the UNIX timestamps that are in double to Instants so I can pass it to outputWithTimestamp. I believe this should be a trivial problem, but I wasn't able to find the solution yet. Thank you.
You can't "cast" a Double to an Instant. You need to pass your timestamp as a constructor argument:
Instant timestamp = new Instant(((Number)row.getTimestamp("timestamp")).longValue());
This assumes the "timestamp" value is in milliseconds. If it's seconds, just multiply by 1000.

Why is assertEquals false if it is the same date? Hibernate

I'm generating one date and saving in a database through hibernate, and when I get the value and I compare with the value before it was inserted. The result is not equal!
I created the date as following
Date rightnow = Calendar.getInstance().getTime();
Task t1 = new Task("My task", rightnow);
taskDao.saveOrUpdate(t1);
Task taskR1 = taskDao.get(t1.getIdTask());
assertEquals("They should have to be equal dates",taskR1.getDate(),t1.getDate());
I'm getting this error
<2014-04-11 23:13:13.0> is different to <Fri Apr 11 23:13:13 CEST 2014>
java.lang.AssertionError:
They should have to be equal dates
expected:<2014-04-11 23:13:13.0>
but was:<Fri Apr 11 23:13:13 CEST 2014>
Extra info related with the problem
Class Task
#Entity
#Table(name = "t_task")
public class Task {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "idTask")
private long idTask;
...
#Column(name = "date")
private Date date;
...
Mysql table t_task
CREATE TABLE IF NOT EXISTS `mytask`.`t_task` (
`idTask` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`date` DATETIME NOT NULL
...
I created a new hashCode() and equals() functions in Task, with only date field and even so it is different.
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((date == null) ? 0 : date.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof Task))
return false;
Task other = (Task) obj;
if (date == null) {
if (other.date != null)
return false;
} else if (!date.equals(other.date))
return false;
return true;
}
Any idea?
This is a complete mess caused by the java.sql.Timestamp messed up design, and by Hibernate returning instances of this class. Indeed, you're storing a java.util.Date instance into your entity. Hibernate transforms that to a java.sql.Timestamp to insert it in the database. But when it reads the data from the database, it doesn't trasform back the Timestamp into a java.util.Date. That works fine, because Timestamp extends Date.
But Timestamp should never have extended Date. Indeed, Date is precise up to the millisecond, whereas Timestamp is precise up to the nanosecond. To be able to compare the nanoseconds parts of two Timestamp, Timestamp overrides the equals() method, but breaks its general contract by doing so. The end result is that you can have date.equals(timestamp) being true, but timestamp.equals(date) being false.
My advice: never compare Date instances with equals(). Use compareTo() instead.
Sun's explanation, working with java client level (not with Hibernate), in the javadoc for java.sql.Timestamp, it states:
Quote:
public class Timestamp extends Date
A thin wrapper around java.util.Date that allows the JDBC API to
identify this as an SQL TIMESTAMP value. It adds the ability to hold
the SQL TIMESTAMP nanos value and provides formatting and parsing
operations to support the JDBC escape syntax for timestamp values.
Note: This type is a composite of a java.util.Date and a separate
nanoseconds value. Only integral seconds are stored in the
java.util.Date component. The fractional seconds - the nanos - are
separate. The Timestamp.equals(Object) method never returns true when
passed a value of type java.util.Date because the nanos component of a
date is unknown. As a result, the Timestamp.equals(Object) method is
not symmetric with respect to the java.util.Date.equals(Object)
method. Also, the hashcode method uses the underlying java.util.Date
implementation and therefore does not include nanos in its
computation.
Due to the differences between the Timestamp class and the
java.util.Date class mentioned above, it is recommended that code not
view Timestamp values generically as an instance of java.util.Date.
The inheritance relationship between Timestamp and java.util.Date
really denotes implementation inheritance, and not type inheritance.
#Test
public void testTimestampVsDate() {
java.util.Date date = new java.util.Date();
java.util.Date stamp = new java.sql.Timestamp(date.getTime());
assertTrue("date.equals(stamp)", date.equals(stamp)); //TRUE
assertTrue("stamp.compareTo(date)", stamp.compareTo(date) == 0); //TRUE
assertTrue("date.compareTo(stamp)", date.compareTo(stamp) == 0); //FALSE
assertTrue("stamp.equals(date)", stamp.equals(date)); //FALSE
}
From javadoc we can figure out that:
Timestamp = java.util.Date + nanoseconds
and
The Timestamp.equals(Object) method never returns true when passed a
value of type java.util.Date because the nanos component of a date is
unknown.
Timestamp compareTo() function
public int compareTo(java.util.Date o) {
if(o instanceof Timestamp) {
// When Timestamp instance compare it with a Timestamp
// Hence it is basically calling this.compareTo((Timestamp))o);
// Note typecasting is safe because o is instance of Timestamp
return compareTo((Timestamp)o);
} else {
// When Date doing a o.compareTo(this)
// will give wrong results.
Timestamp ts = new Timestamp(o.getTime());
return this.compareTo(ts);
}
}
I would suggest you look at what type you are using to store the date in the database. For instance, an Oracle DATE only has precision down to the second level while TIMESTAMP can have down to millisecond like you would with Java date.
http://docs.oracle.com/cd/B19306_01/server.102/b14220/datatype.htm#CNCPT413
For those who are looking for an easy unit testing answer to comparing dates, I have used a SimpleDateFormatter to compare dates as Strings. This allows you to specify the precision you are seeking in the comparison without a bunch of math.
SimpleDateFormatter formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US);
assertEquals(formatter.format(someExpectedDate), formatter.format(someActualDate));
You can modify the format to fit your needs.
The two dates are of different classes (one is a java.util.Date, the other is java.sql.Timestamp), so they are not the same.
Try this to check the date values:
assertEquals(new Date(taskR1.getDate().getTime()), t1.getDate());

JAVA save several DATE into a LIST using a custom Datatype

I want to save several periods of time, which look like that:
public class periodOfTime {
Date from;
Date to;
}
into a List, which looks like that
List <periodOfTime> periodsOfTime = new List<periodOfTime>()
right now.
How can I store !FOR EXAMPLE!
Date s = new Date();
in my list?
My thoughts were, that it can be done with
periodsOfTime.add(s,s)
But it keeps on telling me
The method add(int, periodOfTime) in the type List is not applicable for the arguments (Date, Date)
Can anyone guide me?
Probably I am totally blind right now....
You may want to make getters and setters:)
Try:
PeriodOfTime period = new Period();
period.from = date;
period.to = another_date;
and add to for example ArrayList:
periodsOfTime.add(period);
It will help.

How to check if JSONArray Element is null

I can't figure out how to determine is an element that lives inside a json array is null. To check if the jsonObject itself is null, you simply use:
jsonObject.isNullObject();
But when the object is an array and I want to check if one of the elements of that array is null, this does not work:
jsonArray.get(i).get("valueThatIsNull") == null;
There is also no isNull method available on elements of an array. How do I check if values inside a jsonarray are null? It might help to know that I am passing over a null object from javascript. Maybe null does not mean the same thing in java when it is passed from javascript in json format, but I have also tried putting parentheses around the null and it still does not work.
I am posting some actual source code to help make this clearer. The jsonObject is a part of the jsonArray and the object has multiple values because it iself is an object.
JSONObject mapItem = jsonArray.getJSONObject(i);
int id = mapItem.has("id") ? mapItem.getInt("id") : -1;
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
java.util.Date date = null;
Date sqlDate = null;
if(mapItem.has("date")) {
String dateStr = mapItem.getString("date");
if(!dateStr.equals("null")) {
date = dateFormat.parse(mapItem.getString("date").substring(0, 10)); //Convert javascript date string to java.
sqlDate = new Date(date.getTime());
}
Try .isNull():
For your example:
if(!mapItem.isNull("date")) {
//Value is not null
}
However, to answer the title of this question, "how to tell if a JSONArray element is null", use .equals()
So, to check if index 1 is null:
if (!jsonArray.get(1).equals(null)) {
//jsonArray[1] is not null
}
I guess json passes null values as strings, so you can't check null as a java element. Instead treat the null value as a string as check this way:
if(!mapItem.getString("date").equals("null")) {
//Value is not null
}
I have updated the code snippet in the original question to a working version.
try JSONArray's method
public boolean isNull (int index)
In fact, it uses "null" string comparing to the content
JSONObject.NULL.equals(this.opt(index));

Categories

Resources