Skip to content

Conversation

@eamonnmcmanus
Copy link
Member

@eamonnmcmanus eamonnmcmanus commented Nov 25, 2025

Add type adapters for java.time classes.

These adapters essentially freeze the JSON representation thatReflectiveTypeAdapterFactory established by default, based on the private fields of java.time classes. That's not a great representation, but it is understandable. Changing it to anything else would break compatibility with systems that are expecting the current format.

If Gson had been updated with java.time adapters at the time the java.time API was added, the representation would surely have been something else, probably ISO standard formats. We can potentially supply non-default adapters for that, but we'll still need to have these legacy adapters by default.

I've been meaning to make this change for a while, but the need to do so becomes more urgent with this JDK
commit
which makes a number of java.time fields transient. That means that, in JDK 26, the reflective-based adapter will no longer work with the classes that were changed.

This addresses #1059 and #739. All relevant classes in the java.time package are covered.

(Google internal bug reference: b/463237567.)

These adapters essentially freeze the JSON representation that
`ReflectiveTypeAdapterFactory` established by default, based on the
private fields of `java.time` classes. That's not a great
representation, but it is understandable. Changing it to anything else
would break compatibility with systems that are expecting the current
format.

If Gson had been updated with `java.time` adapters at the time the
`java.time` API was added, the representation would surely have been
something else, probably ISO standard formats. We can still supply
non-default adapters for that, but we'll still need to have these legacy
adapters by default.

I've been meaning to make this change for a while, but the need to do so
becomes more urgent with [this JDK
commit](openjdk/jdk@cc05530)
which makes a number of `java.time` fields `transient`. That means that
the reflective-based adapter will no longer work with the classes that
were changed.
I think it is time to do this, but obviously it should be a separate PR.
}

@Override
@SuppressWarnings("JavaDurationGetSecondsGetNano")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huh, I would have hoped that the getSeconds and getNano calls below were close enough to avoid this warning :(

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what you mean? The warning is supposed to prevent you from calling getSeconds() when you meant toSeconds().

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://errorprone.info/bugpattern/JavaDurationGetSecondsGetNano:

If you call duration.getNano(), you must also call duration.getSeconds() in ‘nearby’ code.

I get the impression that the check would be happy with foo(duration.getSeconds(), duration.getNano()) but not the array case. But I see no other examples in my depot search for ([{]|new.*\[)[^\042]*getSeconds.*getNano lang:java, so I don't think I'll bother to file a feature request.

(I forget where we landed with getSeconds vs. toSeconds. I just know that I got sad about the various get* and to* methods, including the to*Part methods, in b/201676318.)

eamonnmcmanus and others added 9 commits December 18, 2025 16:09
* Move the new `TypeAdapter` implementations into a new class
  `JavaTimeTypeAdapters`. This allows us to omit that class from Android
  builds where it otherwise triggers warnings about SDK levels.

* Ensure that every `java.time` class that needs a `TypeAdapter` has
  one. This doesn't include "subpackages" `java.time.*` like
  `java.time.chrono`, where it doesn't appear that there are any classes
  that are likely to be serialized to JSON.

* Fix the handling of `ZoneId` and its subclasses.
* refactor: slightly optimize ConstructorConstructor

* Update comments

Co-authored-by: Marcono1234 <Marcono1234@users.noreply.github.com>

* spotless apply

Co-authored-by: Marcono1234 <Marcono1234@users.noreply.github.com>

---------

Co-authored-by: Marcono1234 <Marcono1234@users.noreply.github.com>
I copied the internal version that was running on Google's
infrastructure, and some adjustments were needed.
This still doesn't pass with a local build, and I may need to debug an
OSGi problem.
}

@Override
@SuppressWarnings("JavaDurationGetSecondsGetNano")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://errorprone.info/bugpattern/JavaDurationGetSecondsGetNano:

If you call duration.getNano(), you must also call duration.getSeconds() in ‘nearby’ code.

I get the impression that the check would be happy with foo(duration.getSeconds(), duration.getNano()) but not the array case. But I see no other examples in my depot search for ([{]|new.*\[)[^\042]*getSeconds.*getNano lang:java, so I don't think I'll bother to file a feature request.

(I forget where we landed with getSeconds vs. toSeconds. I just know that I got sad about the various get* and to* methods, including the to*Part methods, in b/201676318.)

It appears that sometimes the clauses being checked for appear in the
other order, possibly because of a `HashMap` or the like somewhere in
the guts of OSGi. I haven't seen this on GitHub, but I do see it when
running locally with Google's JDK, which has more hash randomization.
It's enough just to swap the two clauses of a line when they are not in
the expected order.

Also, unrelatedly, update `protobuf-maven-plugin`.
@eamonnmcmanus eamonnmcmanus merged commit c47db7b into google:main Dec 23, 2025
14 of 15 checks passed
@eamonnmcmanus eamonnmcmanus deleted the javatime branch December 23, 2025 22:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants