Skip to content
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

GSON Serialization/Deserialization of Java 8 Date API #1059

Open
reinaldomjr opened this issue Apr 7, 2017 · 12 comments
Open

GSON Serialization/Deserialization of Java 8 Date API #1059

reinaldomjr opened this issue Apr 7, 2017 · 12 comments
Labels
enhancement java8 Issues related to making Java 8 the minimum supported version

Comments

@reinaldomjr
Copy link

reinaldomjr commented Apr 7, 2017

When serializing / deserializing an object with the Date and Time classes of the new java.time API, the results are diferent from expected.

For example, here's a java.util.Date serialized with gson (using version 2.8.0):

"created": "2017-04-07T18:07:00",

and here's a java.time.LocalDate:

"expiration": {
"year": 2017,
"month": 4,
"day": 7
}

the expected result for javatime api was a ISO-8601.

@reinaldomjr reinaldomjr changed the title GSON Serialization/Deserialization of Java 8 Data API GSON Serialization/Deserialization of Java 8 Date API Apr 7, 2017
@JakeWharton
Copy link
Contributor

This is due to some historical baggage where Gson will happily serialize any object inside the platform package (java.*). Ideally Gson would throw an error when you did this, but alas, we can't make that change. Also Gson's built-in support of java.util.Date is also historical baggage we cannot remove or change.

The correct solution here would be to register your own type adapter for the java.time.* types so that they show up as ISO 8601 when serialized and deserialization parses them appropriately.

A quick search yields https://github.com/gkopff/gson-javatime-serialisers which you may just be able to drop in, but otherwise building a TypeAdapter yourself for these shouldn't be too bad.

@kkolman
Copy link

kkolman commented Jun 29, 2017

a) still it would be great to have an "official" gson plugin/package with Java 8 types support
b) a note in https://github.com/google/gson/blob/master/UserGuide.md with the explanation about targetting Java 6 would helpe otherwise

@jugimaster
Copy link

Dates come in from JSON as string values, right?

I keep seeing examples of registering adapters for specific Java classes like ZonedDateTime etc, but how would Gson know that you want to convert a particular incoming string value into a ZonedDateTime specifically?

@joffrey-bion
Copy link

joffrey-bion commented Jan 15, 2018

@jugimaster Because you tell Gson the expected class when deserializing:

SomeClass obj = gson.fromJson(jsonString, SomeClass.class);

So Gson would either know it from there, or if your ZonedDateTime is a field of the class, then Gson will know by reflection that this field is supposed to be a ZonedDateTime (unless you use an abstract superclass/interface).

@jugimaster
Copy link

Because you tell Gson the expected class when deserializing

But I'm not using JavaBeans/"domain model classes" - I just have Maps, and I was calling Gson from Clojure too.

Can strings be converted into Dates when deserializing into a Map?

@joffrey-bion
Copy link

joffrey-bion commented Jan 29, 2018

@jugimaster I'm not familiar with clojure unfortunately, but as far as I remember in Java, if you're using a Map<String, Date>, Gson would know the expected type for your map's values is Date.

However, you seem to be using a "map of maps" kind of structure without generic type information (even maybe using mixed types as values in your maps), and in this case I don't see how Gson could possibly infer a more accurate type than the JSON type itself, which would be String in your case.

Again, I'm speaking for Java, but I guess if you want statically typed data, you should define your classes. If you don't, then you should expect to handle this kind of conversions yourself at runtime.
Please someone from the Gson team correct me if I'm wrong.

@jugimaster
Copy link

However, you seem to be using a "map of maps" kind of structure without generic type information (even maybe using mixed types as values in your maps), and in this case I don't see how Gson could possibly infer a more accurate type than the JSON type itself, which would be String in your case.

Right :)

But with Jackson, I was able to configure my own class to handle incoming Strings, and convert the ones that represent dates into Date instances. I couldn't figure out how to do that with Gson.

I may be completely missing something here, of course.

@remal
Copy link

remal commented Dec 5, 2023

Dear maintainers,

Is it possible to implement it? We have Java 21 released, and java.time.* classes are used a lot

@sergey-morenets
Copy link

Dear maintainers,

Is it possible to implement it? We have Java 21 released, and java.time.* classes are used a lot

Hi @remal

I guess it's not possible to implement that now because Gson still uses Java 7 source compatibility. So it just can't support Java 8 types. So the only approach is to use custom type adapters or migrate to another serialization library.

@eamonnmcmanus
Copy link
Member

I guess it's not possible to implement that now because Gson still uses Java 7 source compatibility. So it just can't support Java 8 types. So the only approach is to use custom type adapters or migrate to another serialization library.

Well, a couple of comments. First, we could always use reflection to allow the java.time code to work on Java 7. We already do something similar for Java 16's records. Second, perhaps it is time to drop Java 7 support and move to Java 8. I think Android tooling is pretty good about making that work even on old Android versions, and that's the only reason I know of for continuing to support Java 7.

The existing support for serializing and deserializing Date is kind of disastrous and we would have an opportunity to do better with Instant, ZonedDateTime, etc. The main concern I would have is that there are probably users who are depending on the existing default serialization and deserialization shown in the original comment, so I think we would have to have a configuration option to enable the new adapters. Then that is not very different from just using an existing third-party package, as suggested by @JakeWharton in the first reply above.

A further wrinkle is that the default serialization doesn't work with recent JDK versions unless you use the appropriate --add-opens. We might detect the InaccessibleObjectException that you get otherwise and rethrow it with an exception message pointing to the troubleshooting guide, and perhaps also put a pointer to the third-party library in that guide. We could conceivably also enable new built-in serializers and deserializers when that happens, but for compatibility those would have to use the somewhat unnatural format mentioned in the original comment instead of the ISO 8601 or RFC 3339 that people would presumably expect.

@Marcono1234
Copy link
Collaborator

so I think we would have to have a configuration option to enable the new adapters

Should this be done then as new GsonBuilder method, and not by publicly exposing TypeAdapter or TypeAdapterFactory implementations? This would be consistent with the remaining Gson code where all TypeAdapter and TypeAdapterFactory classes are implementation details (not a strong argument though), and would allow enabling the adapters by default in the future and deprecating (and removing?) the GsonBuilder methods again.

Maybe it would be good then to also add opt-in support other Java 8 types, such as java.util.Optional (#1102), and then name the method for example GsonBuilder.addJava8Adapters()?

We might detect the InaccessibleObjectException that you get otherwise and rethrow it with an exception message pointing to the troubleshooting guide

That sounds like a good idea. Detecting if this exception occurs for one of the types which will have opt-in support should definitely be possible.

We could conceivably also enable new built-in serializers and deserializers when that happens

This could risk though that new users (who haven't used java.time classes before) start relying on this, even though it would be better if they used the proper ISO format. So in case we want to still support the old reflection-based structure, it might be better if that has to be explicitly enabled. What do you think?

@eamonnmcmanus eamonnmcmanus added the java8 Issues related to making Java 8 the minimum supported version label Mar 2, 2024
@ktdilsiz
Copy link

ktdilsiz commented Dec 4, 2024

Any updates? This is blocking us from updating to Java17 :(

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement java8 Issues related to making Java 8 the minimum supported version
Projects
None yet
Development

No branches or pull requests

10 participants