Repository navigation
JDK21 toJson failure #2689
Copy link
Copy link
Open
Labels
Description
Gson version
version 2.10.1
Using JDK 21 to perform fromJson, the Date type contains hidden characters causing the failure of the toJson operation.
In GitHub issues, it seems that I cannot illustrate it, so I will use images to show

public static void main(String[] args) {
String jdk17="{\"clientId\":\"123\",\"secret\":\"123\",\"creator\":\"trump\",\"gmtCreated\":\"Dec 14, 2023, 11:07:35 AM\",\"gmtModified\":\"Dec 15, 2023, 4:45:51 PM\"}";
OauthClient oc17 = gson.fromJson(jdk17, OauthClient.class);
String jdk21= "{\"clientId\":\"123\",\"secret\":\"123\",\"creator\":\"trump\",\"gmtCreated\":\"Mar 21, 2022, 11:03:07 AM\",\"gmtModified\":\"Mar 21, 2022, 11:03:07 AM\"}";
OauthClient oc21 = gson.fromJson(jdk21, OauthClient.class);
}
Exception in thread "main" com.google.gson.JsonSyntaxException: Failed parsing 'Mar 21, 2022, 11:03:07 AM' as Date; at path $.gmtCreated
at com.google.gson.internal.bind.DateTypeAdapter.deserializeToDate(DateTypeAdapter.java:90)
at com.google.gson.internal.bind.DateTypeAdapter.read(DateTypeAdapter.java:75)
at com.google.gson.internal.bind.DateTypeAdapter.read(DateTypeAdapter.java:46)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.readIntoField(ReflectiveTypeAdapterFactory.java:212)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$FieldReflectionAdapter.readField(ReflectiveTypeAdapterFactory.java:433)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:393)
at com.google.gson.Gson.fromJson(Gson.java:1227)
at com.google.gson.Gson.fromJson(Gson.java:1137)
at com.google.gson.Gson.fromJson(Gson.java:1047)
at com.google.gson.Gson.fromJson(Gson.java:982)
at cn.tongdun.arch.luc.biz.OauthClientBusinessService.main(OauthClientBusinessService.java:78)
Caused by: java.text.ParseException: Failed to parse date ["Mar 21, 2022, 11:03:07 AM"]: Invalid number: Mar
at com.google.gson.internal.bind.util.ISO8601Utils.parse(ISO8601Utils.java:279)
at com.google.gson.internal.bind.DateTypeAdapter.deserializeToDate(DateTypeAdapter.java:88)
... 10 more
Caused by: java.lang.NumberFormatException: Invalid number: Mar
at com.google.gson.internal.bind.util.ISO8601Utils.parseInt(ISO8601Utils.java:316)
at com.google.gson.internal.bind.util.ISO8601Utils.parse(ISO8601Utils.java:133)
... 11 more
Java / Android version
jdk21
Used tools
- Maven; version:
- Gradle; version:
- ProGuard (attach the configuration file please); version:
- ...
Description
Expected behavior
Actual behavior
Reproduction steps
1.Convert an object containing a date variable to JSON.
2.Copy the output JSON string.
3.When pasted into an editor like IntelliJ IDEA, hidden characters appear with JDK 21, while JDK 17 does not exhibit this behavior for such operations.
Exception stack trace
Reactions are currently unavailable
Activity
funky-eyes commentedon May 29, 2024
adoptium/adoptium-support#1101
jerboaa commentedon May 29, 2024
The relevant JDK enhancement is JDK-8284840 - CLDR update to version 42.0. See also https://bugs.openjdk.org/browse/JDK-8324308 (and friends), for similar issues.
Marcono1234 commentedon May 29, 2024
Gson unfortunately uses a human-readable date format by default. We noticed the same (or a very similar issue) you are seeing here in Gson's unit tests: #2450
There is the idea to possibly change the default date format used by Gson in future versions, see #2472, but it is unclear if that will happen since it could be considered backward incompatible.
The best solution at the moment might be to specify a custom date format with
GsonBuilder.setDateFormat(String)or to register a customTypeAdapterforDate.Otherwise, if you keep using Gson's default date format a similar issue might happen in future JDK versions again.
funky-eyes commentedon May 30, 2024
It seems like this is a destructive way of modification. The application that I have already launched will be affected by setDateFormat. For example, if I toJSON some data into Redis and then fromJson to an object when using it, when some data is written by the node using setDateFormat, an exception will occur when other nodes read it. It is impossible to smoothly upgrade. Of course, for Redis, I can switch to another database to solve the problem. If it is stored in other databases such as MySQL, historical data will be seriously affected!
Marcono1234 commentedon May 30, 2024
Another solution could be to write a
TypeAdapterFactorywhich creates an adapter that changes the serialization date format, and for deserialization tries to use the same format as well but if that fails falls back to the default adapter.Here is a sample implementation for this:
IsoDateAdapterFactory(click to expand)Note that I haven't tested this extensively. And if parsing fails, the JSON path in the exception message will not be that helpful, saying
$(root element) instead of the actual path. Maybe that could be improved a bit by wrapping the exception and includingJsonReader.getPreviousPath().And then registering it like this:
funky-eyes commentedon May 31, 2024
Thank you for your guidance. I will proceed with the relevant attempts.
brachaA commentedon Sep 29, 2024
I got a similar error when working on JDK21 and Gson,
Gson doesn't success to parse Level class:
Gson gson = new GsonBuilder().disableHtmlEscaping().create();
return gson
.fromJson(new String(buffer, StandardCharsets.UTF_8), Level.class);
java.util.logging.Level
error
LevelSerializer.Deserialize
at com.google.gson.Gson.fromJson(Gson.java:848)
at com.google.gson.Gson.fromJson(Gson.java:877)
at com.google.gson.Gson.fromJson(Gson.java:928)
at com.google.gson.Gson.fromJson(Gson.java:962)
at com.google.gson.Gson.getAdapter(Gson.java:489)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:102)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:166)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:117)
at com.google.gson.Gson.getAdapter(Gson.java:489)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:102)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:159)
at com.google.gson.internal.reflect.UnsafeReflectionAccessor.makeAccessible(UnsafeReflectionAccessor.java:44)
at java.base/java.lang.reflect.Field.setAccessible(Field.java:177)
at java.base/java.lang.reflect.Field.checkCanSetAccessible(Field.java:183)
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:315)
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:367)
at java.base/java.lang.reflect.AccessibleObject.throwInaccessibleObjectException(AccessibleObject.java:391)
Marcono1234 commentedon Oct 6, 2024
@brachaA, can you please provide the full exception message, and ideally a small complete code sample for reproducing this? Additionally, it might be better to create a separate GitHub issue first until we are sure that they are the same underlying problem, to avoid that this issue here becomes off-topic.
clydebaron2000 commentedon Jun 10, 2025
I am also having issues. The error is reproducible with any POJO with a Date attribute similar to @funky-eyes. @Marcono1234 I see that the backwards compatible iso date format issue is closed out. Have the plans for the fix been abandoned?
While it is true there are workarounds for this issue, shouldn't GSON by default not run into
java.util.Dateformatting issues by design?Marcono1234 commentedon Jun 23, 2025
Which one do you mean? #2472 is still open, but it is only a proposal for now.
Ideally yes. I am not a direct member of this project and was not involved when Gson was created, but I guess back then using the the human readable format seemed like a good and easy solution. Now in retrospective we know that due to changes to Unicode CLDR data and interoperability concerns this format is not ideal, and using ISO 8601 would be better1.
Footnotes
Note also that back then the
java.timepackage did not exist so Gson would have needed its own ISO 8601 formatting and parsing code, or include a separate dependency just for that. And even now, due to the minimum supported Android versions Gson cannot usejava.timeyet. ↩