Skip to content

Gson serialize/deserialize rountrip of java.time.OffsetDateTime drops the time zone component #1526

Not planned
@tomasaschan

Description

@tomasaschan

The following snippet illustrates the problem:

final Gson gson = new GsonBuilder().create();
final OffsetDateTime before = OffsetDateTime.now();
System.out.println(String.format("Before:     %s", before));
final String serialized= gson.toJson(before);
System.out.println(String.format("Serialized: %s", serialized));
final OffsetDateTime after = gson.fromJson(serialized, OffsetDateTime.class);
System.out.println(String.format("After:      %s", after));

One run output the following:

Before:     2019-05-03T16:31:25.171+02:00
Serialized: {"dateTime":{"date":{"year":2019,"month":5,"day":3},"time":{"hour":16,"minute":31,"second":25,"nano":171000000}},"offset":{"totalSeconds":7200}}
After:      2019-05-03T16:31:25.171null

Note that on the last line, after the serialization roundtrip, the timezone is dropped. Why? Is this a bug in gson, or a configuration error on my part?

This is with gson 2.8.5 and

>java -version
openjdk version "1.8.0_212"
OpenJDK Runtime Environment (Zulu 8.38.0.13-CA-win64) (build 1.8.0_212-b04)
OpenJDK 64-Bit Server VM (Zulu 8.38.0.13-CA-win64) (build 25.212-b04, mixed mode)

Activity

tomasaschan

tomasaschan commented on May 4, 2019

@tomasaschan
Author

After doing some research on this, I think I can summarize the root cause:

  • When deserializing a ZoneOffset, gson sets the totalSeconds, but not the id (probably as intended, because id is marked transient)
  • When calling toString on a ZoneOffset, it simply outputs its id
  • When calling toString on an OffsetDateTime, it returns datetime.toString() + offset.toString()

I thus, all the actual information does survive the round-trip, but the redundancy in ZoneOffset is not handled according to the, presumed, intended behavior of the type.

I understand that it's too late to change gson's handling of serializing OffsetDateTime and friends to use eg ISO date strings instead, but IIUC it should be possible to adapt how gson deserializes ZoneOffset specifically, to calculate and set the ID string too (for example, {"totalSeconds": 7200} should have the ID string set to "+02:00").

Is this something that should be done inside gson, or as a plugin? Would a PR with this functionality have any chance of being accepted?

janos-laszlo

janos-laszlo commented on Dec 7, 2019

@janos-laszlo

I tried it with a custom TypeAdapter:
https://www.tutorialspoint.com/gson/gson_custom_adapters.htm
and solves this problem in my case

cesarochoa2006

cesarochoa2006 commented on Jul 7, 2021

@cesarochoa2006

The following snippet illustrates the problem:

final Gson gson = new GsonBuilder().create();
final OffsetDateTime before = OffsetDateTime.now();
System.out.println(String.format("Before:     %s", before));
final String serialized= gson.toJson(before);
System.out.println(String.format("Serialized: %s", serialized));
final OffsetDateTime after = gson.fromJson(serialized, OffsetDateTime.class);
System.out.println(String.format("After:      %s", after));

One run output the following:

Before:     2019-05-03T16:31:25.171+02:00
Serialized: {"dateTime":{"date":{"year":2019,"month":5,"day":3},"time":{"hour":16,"minute":31,"second":25,"nano":171000000}},"offset":{"totalSeconds":7200}}
After:      2019-05-03T16:31:25.171null

Note that on the last line, after the serialization roundtrip, the timezone is dropped. Why? Is this a bug in gson, or a configuration error on my part?

This is with gson 2.8.5 and

>java -version
openjdk version "1.8.0_212"
OpenJDK Runtime Environment (Zulu 8.38.0.13-CA-win64) (build 1.8.0_212-b04)
OpenJDK 64-Bit Server VM (Zulu 8.38.0.13-CA-win64) (build 25.212-b04, mixed mode)

Please check this project. I have found the OffsetDateTime converter of theirs fully working and usefull
https://github.com/aaronweihe/ThreeTen-Backport-Gson-Adapter

Marcono1234

Marcono1234 commented on Aug 6, 2022

@Marcono1234
Collaborator

The underlying issue here is that Gson does not have any built-in type adapters for the java.time classes (#1059) and you are (by accident?) relying on reflection-based serialization for these classes. This should be avoided because it makes you dependent on the implementation details of these classes.

As mentioned in the comments above, prefer using a custom type adapter for the class.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @tomasaschan@Marcono1234@cesarochoa2006@janos-laszlo

        Issue actions

          Gson serialize/deserialize rountrip of java.time.OffsetDateTime drops the time zone component · Issue #1526 · google/gson