Add API for retrieving type arguments of parameterized type #1952
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Purpose
Resolves #333
Probably also resolves #1334
When users write custom type adapters for their generic classes, they need to get the resolved type arguments to get the respective adapters for them. A common example are collection types similar to
Map<K, V>
orList<E>
. Gson internally has logic for retrieving type arguments, but it does not expose this as public API. This leads to users repeatedly writing the same code. Additionally user-written code is sometimes incomplete because it forgets to consider that subtypes might have different type parameters, e.g.StringKeyMap<V> implements Map<String, V>
.This pull request adds one method to
TypeToken
for simplifying this:TypeToken.getTypeArguments(Class<?> supertype)
Usage example (snippet from a hypothetical
Map<K, V>
TypeAdapterFactory):Implementation
Overlaps in some parts with #1753
The main implementation is based on
$Gson$Types#getSupertype
which is already used by the Collection and Map type adapter factories. However unlike those factories thegetTypeArguments
method performs additional resolution by using (transitive) type bounds of type variables and wildcards. This matches more closely how the type behaves when the user programs against its API, e.g. for a raw type ofNumberCollection<E extends Number>
only Number instances can be added. SimilarlygetTypeArguments
would return Number as type argument.For type variables it only considers the first bound (and ignores other bounds, if any); otherwise the implementation might become too complex and additionally Gson's TypeToken cannot represent intersection types properly.
To support this properly, TypeToken was changed to report the erasure of the first bound of a TypeVariable as raw type instead of just Object. However, this should most likely affect only very few existing projects, probably mostly cases where raw types were used or type variables were captured using TypeToken (which is error-prone and might be good to disallow in the future, see also #1753).
The implementations of Collection and Map type adapter factories have not been changed to use
getTypeArguments
to not change their behavior too much; though it might be worth considering this in the future.Open questions
List<E>
withE
being a type variable, then that is not resolved. This assumes that the type adapter forList
would then also callgetTypeArguments
to resolveE
, but for the built-in adapters this is currently not the case.The question is whether all occurrences of type variables and wildcards should be resolved. If so this should probably become part of
$Gson$Types.resolve
, activated with a boolean parameter.