Skip to content

Use the runtime type for a wildcard element type - #3112

Open
HuzaifaChaudary wants to merge 1 commit into
google:mainfrom
HuzaifaChaudary:wildcard-runtime-type
Open

Use the runtime type for a wildcard element type#3112
HuzaifaChaudary wants to merge 1 commit into
google:mainfrom
HuzaifaChaudary:wildcard-runtime-type

Conversation

@HuzaifaChaudary

Copy link
Copy Markdown

Fixes #1870

getRuntimeTypeIfMoreSpecific only looks at the runtime type for a Class or a
TypeVariable . ? extends Base is a WildcardType , so it is neither , and the adapter for
the declared bound is used instead :

List<? extends Base>   ->  {"list":[{"a":"1"}]}            b is missing
List<Base>             ->  {"list":[{"b":"2","a":"1"}]}

same value , same field , different json .

a wildcard says nothing more than its upper bound , so this reads the bound and then decides
the same way it already does for a plain type . the bound is only used to make the decision ,
the declared type is still what gets kept when it is parameterized , so ? extends List<String>
behaves like List<String> and does not lose its type arguments . that is why this reads the
bound rather than just adding || type instanceof WildcardType , which would swap in the raw
runtime class and drop them .

while testing i found a worse case of the same cause that is not in the report .
List<? extends CharSequence> holding a String and a StringBuilder serialized as
[{},{}] , because gson fell back to a reflective adapter for the interface . the strings were
simply gone . List<CharSequence> gives ["s","t"] . that is fixed by the same change .

four tests added , covering a wildcard list , a wildcard map value , and a wildcard reached
through a type variable . the fourth goes the other way and pins that
Collection<? extends ParameterizedBase<String>> still keeps the declared type , so the change
is not too loose . it passes with and without .

4637 tests pass in the gson module , 0 failures , and the full reactor is 4856 across all eight
modules . spotless:check is clean .

one related thing i deliberately left out . registerTypeAdapter(Base.class, adapter) is still
ignored when the element type is ? extends Base , because the lookup token never matches one
registered for Base.class . that needs the wildcard stripped at adapter lookup time , where
there is already a // TODO: strip wildcards? in GsonTypes , and it is a wider change to
your internals , so it seemed better to leave that call to you . this change still improves that
case , the subclass fields stop disappearing .

@google-cla

google-cla Bot commented Sep 5, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@HuzaifaChaudary

Copy link
Copy Markdown
Author

@googlebot I signed it!

a field like List<? extends Base> holding a Sub lost the fields that Sub
adds , because getRuntimeTypeIfMoreSpecific only looked at the runtime
type for a Class or a type variable , and ? extends Base is neither . so
List<? extends Base> and List<Base> gave different json for the same
value .

a wildcard says nothing more than its upper bound , so this reads the
bound and then decides the same way as before . when the bound is a
parameterized type the declared type is kept , same as gson already does
for a plain parameterized type , because the runtime class would drop the
type arguments .

closes google#1870
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.

[bug] sub class field missing during serialization if collection's element type is a WildcardType

1 participant