-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix DateFormat time zone is not restored and add Test. #2549
Conversation
I just fetch and pull the new code, and I use
And i git clone the gson' master branch code and use |
Which JDK and Maven version are you using? Could you please provide the output of |
Thank you for your reply. there is output of
|
It looks like you are using JDK 21; could you please try JDK 17 instead? Gson currently does not support building with JDK 21, see #2501. |
ok, thank you for your help, I solve the error, and I am trying to do the picture which you mentioned before and add the test. |
Hello, I had finished the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot! I have added a few small review comments but generally at least to me this PR looks good.
TimeZone originalTimeZone = format.getTimeZone(); // Save the original time zone | ||
utilDate = format.parse(s); | ||
format.setTimeZone(originalTimeZone); // Restore the original time zone after parsing |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use try-finally
here as well, to be safe (in case time zone was already changed despite an exception being thrown):
TimeZone originalTimeZone = format.getTimeZone(); // Save the original time zone | |
utilDate = format.parse(s); | |
format.setTimeZone(originalTimeZone); // Restore the original time zone after parsing | |
TimeZone originalTimeZone = format.getTimeZone(); // Save the original time zone | |
try { | |
utilDate = format.parse(s); | |
} finally { | |
format.setTimeZone(originalTimeZone); // Restore the original time zone after parsing | |
} |
(you might to have to reformat the code above)
TimeZone originalTimeZone = format.getTimeZone(); // Save the original time zone | ||
Date date = format.parse(s); | ||
format.setTimeZone(originalTimeZone); // Restore the original time zone |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use try-finally
here as well:
TimeZone originalTimeZone = format.getTimeZone(); // Save the original time zone | |
Date date = format.parse(s); | |
format.setTimeZone(originalTimeZone); // Restore the original time zone | |
TimeZone originalTimeZone = format.getTimeZone(); // Save the original time zone | |
try { | |
date = format.parse(s); | |
} finally { | |
format.setTimeZone(originalTimeZone); // Restore the original time zone after parsing | |
} |
(you might to have to reformat the code above)
gson/src/test/java/com/google/gson/internal/bind/DefaultDateTypeAdapterTest.java
Show resolved
Hide resolved
Date deserializedDate = gson.fromJson("\"1970-01-01 00:00 PST\"", Date.class); | ||
|
||
// Serialize the deserialized date object again | ||
String jsonAfterDeserialization = gson.toJson(deserializedDate); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe this should rather call toJson(originalDate)
; otherwise if deserializedDate
is incorrect due to a bug we would get confusing failures here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hyt
assertEquals("\"1970-01-01 00:00 UTC\"", json); | ||
|
||
// Deserialize a date string with the PST timezone | ||
Date deserializedDate = gson.fromJson("\"1970-01-01 00:00 PST\"", Date.class); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe add an assertion here that the date was parsed correctly, I assume it would be this:
Date deserializedDate = gson.fromJson("\"1970-01-01 00:00 PST\"", Date.class); | |
Date deserializedDate = gson.fromJson("\"1970-01-01 00:00 PST\"", Date.class); | |
assertThat(deserializedDate).isEqualTo(new Date(28800000)); |
String jsonAfterDeserialization = gson.toJson(deserializedDate); | ||
// The expectation is that the date, after deserialization, when serialized again should still | ||
// be in the UTC timezone | ||
assertEquals("\"1970-01-01 08:00 UTC\"", jsonAfterDeserialization); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use Truth instead of the JUnit methods here; that will leads to better failure messages and makes the assertion easier to read:
assertEquals("\"1970-01-01 08:00 UTC\"", jsonAfterDeserialization); | |
assertThat(jsonAfterDeserialization).isEqualTo("\"1970-01-01 08:00 UTC\""); |
thanks I had change the pr description, and add
|
@@ -60,17 +60,18 @@ public java.sql.Date read(JsonReader in) throws IOException { | |||
return null; | |||
} | |||
String s = in.nextString(); | |||
TimeZone originalTimeZone = format.getTimeZone(); // Save the original time zone |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please move this and the setTimeZone
call inside the synchronized (this) { ... }
block. Type adapters must be thread-safe and with the current implementation there could be a race condition.
Or rewrite this so that the synchronized
block covers the try
; I guess that should be fine as well, e.g.:
synchronized (this) {
TimeZone originalTimeZone = format.getTimeZone(); // Save the original time zone
try {
Date utilDate = format.parse(s);
return new java.sql.Date(utilDate.getTime());
} catch (ParseException e) {
throw new JsonSyntaxException("Failed parsing '" + s + "' as SQL Date; at path " + in.getPreviousPath(), e);
} finally {
format.setTimeZone(originalTimeZone); // Restore the original time zone after parsing
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is my mistake; I did not carefully read the code review you provided at the beginning.
@@ -61,16 +61,17 @@ public Time read(JsonReader in) throws IOException { | |||
return null; | |||
} | |||
String s = in.nextString(); | |||
TimeZone originalTimeZone = format.getTimeZone(); // Save the original time zone |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as #2549 (comment)
You have to look further up in the Maven log output then; there should be one or more "[WARNING] ..." lines for the maven-compiler-plugin. Alternatively, you can also push the non-working code if you want so that we can see the error message here in the GitHub workflow log, and suggest how to solve it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe that the suggestion in the image to use toJson(originalDate) is unnecessary because I have already performed toJson on both originalDate and deserializedDate, with corresponding assertions for each.
Ok, that is fine for me now because you added assertThat(deserializedDate.getTime()).isEqualTo(...)
.
Just two more small things, see comments.
Date expectedDate = new Date(28800000); // This represents the original date in UTC | ||
String expectedJson = gson.toJson(expectedDate); | ||
assertThat(jsonAfterDeserialization).isEqualTo(expectedJson); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please hardcode the expected JSON string here:
Date expectedDate = new Date(28800000); // This represents the original date in UTC | |
String expectedJson = gson.toJson(expectedDate); | |
assertThat(jsonAfterDeserialization).isEqualTo(expectedJson); | |
assertThat(jsonAfterDeserialization).isEqualTo("\"1970-01-01 08:00 UTC\""); |
Otherwise your current code would fail to detect the bug (if you reverted your setTimeZone
fix) because both gson.toJson(deserializedDate)
and gson.toJson(expectedDate)
would use PST as time zone, and would therefore both be wrong. But because both are wrong in the same way, the test would erroneously pass as successful.
|
||
// Serialize the date object | ||
String json = gson.toJson(originalDate); | ||
assertEquals("\"1970-01-01 00:00 UTC\"", json); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use Truth for assertions here:
assertEquals("\"1970-01-01 00:00 UTC\"", json); | |
assertThat(json).isEqualTo("\"1970-01-01 00:00 UTC\""); |
Thank you for your suggestions; they are helpful for improving my skills. I have made the changes according to your comments. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your work on this! The changes look good to me.
@eamonnmcmanus, could you please have a look?
Just one small note, but you don't have to change the code for that:
I thought a bit more about the gson.toJson(deserializedDate)
in the test. This bothers me a bit because the point is that the time zone of the DateFormat
is not restored. The current test code makes it look a bit as if Date
internally stored a time zone as well (which it doesn't), and as if the DateFormat
'forces' usage of UTC even though the Date
has PST as time zone (again, which is not actually the case).
That is why I think it would have been better to call gson.toJson(originalDate)
a second time instead of gson.toJson(deserializedDate)
, because that makes it clearer that the issue here is with the DateFormat
, and not with the deserialized Date
.
Thank you for your patient guidance, which is meaningful for developing my skills and valuable to me. |
Hello @eamonnmcmanus, if there are any changes that you are still dissatisfied with, or if you think there are areas that can be improved, please let me know. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for doing this! And sorry it took me a while to get to it.
* Fix DateFormat time zone is not restored and add Test. * delete the test and make sure mvn clean test -X can be SUCCESS * delete the test and make sure mvn clean test -X can be SUCCESS * add test * restore the DateFormat time zone in SqlDateTypeAdapter and SqlTimeTypeAdapter * Adjust the code according to the code review feedback. * Adjust the code according to the code review feedback. * Adjust the code according to the code review feedback. * Adjust the Test * fix Werror error * Adjust the DefaultDateTypeAdapterTest according to the code review feedback. --------- Co-authored-by: Carpe-Wang <wangcarpe@126.com>
Purpose
Fix DateFormat time zone is not restored after parsing. Fixes #2547
Description
Before attempting to parse the date string, save the current timezone for each DateFormat object. Use a finally block to ensure that the original timezone is restored for each DateFormat object.
Checklist
This is automatically checked by
mvn verify
, but can also be checked on its own usingmvn spotless:check
.Style violations can be fixed using
mvn spotless:apply
; this can be done in a separate commit to verify that it did not cause undesired changes.null
@since $next-version$
(
$next-version$
is a special placeholder which is automatically replaced during release)TestCase
)mvn clean verify javadoc:jar
passes without errors