-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
Improve TypeToken
creation validation
#2072
Merged
eamonnmcmanus
merged 13 commits into
google:master
from
Marcono1234:marcono1234/TypeToken-improvements
Apr 19, 2022
Merged
Changes from 12 commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
f8b33f4
Add comments regarding multiple bounds of wildcard
Marcono1234 9faa6c3
Remove WildcardType check in getCollectionElementType
Marcono1234 074ec48
Remove redundant getRawType call from MapTypeAdapterFactory
Marcono1234 a264348
Make TypeToken members private
Marcono1234 0e69593
Remove incorrect statement about TypeToken wildcards
Marcono1234 02b7500
Only allow direct subclasses of TypeToken
Marcono1234 85159c4
Throw exception when TypeToken captures type variable
Marcono1234 11c1d05
Make $Gson$Types members private
Marcono1234 f853dbb
Rename $Gson$Types.getGenericSupertype parameter
Marcono1234 0530cde
Merge branch 'master' into marcono1234/TypeToken-improvements
Marcono1234 4436078
Improve tests and handle raw TypeToken supertype better
Marcono1234 446bf92
Make some $Gson$Types members package-private again to prevent synthe…
Marcono1234 cba0307
Remove TypeToken check for type variable
Marcono1234 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we were designing the code now, this would be a good check to make. In the deserialization case allowing a type variable allows a silent unchecked conversion. But there's a lot of existing client code which might be working perfectly well with these arguably-illegitimate captured type variables. To get an idea, I ran this change against all of Google's internal tests. There were two test failures due to this new exception. One of them looked like this, in outline:
Then subclasses implement
getDtoClass()
appropriately.I think this code would work just as well if the declaration were this:
However I also think the code is correct as written. It wouldn't be correct if it were trying to deserialize a
List<D>
, but here apparently the code only serializes.So I think this change breaks some correct code, and I don't feel we can justify that.
(The other test failure was deserializing, but it also apparently worked despite being unsound.)
The rest of the PR looks like a good set of improvements, if you want to just remove the
verifyNoTypeVariable
part.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even serialization can be broken due to this. For your case let's imagine there is a
Dto
subclass which has a custom type adapter. Then serializing it withresultToJson(D)
works fine, butresultToJson(List<D>)
erroneously uses the adapter forDto
instead ofD
.The current situation is really unfortunate... I think it would be really useful to have the type variable check. For this PR I can omit it, but I am not sure about completely giving up on that check.
Luckily if the type variable has no bounds, then
ObjectTypeAdapter
uses the runtime type adapter, so at least in these cases it is probably not causing such big issues (unless a user explicitly wanted to serialize as supertypeT
instead of using the runtime type, if they have separate adapters).As side note: I would recommend changing your
AbstractAction
code to construct theresultListType
using Gson'sTypeToken.getParameterized(Type, Type...)
(if possible), that would fix all issues with it. Sorry if that is a bit presumptuous 😅There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@eamonnmcmanus, what do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My assumption is that if Google's code includes two unrelated tests that fail with this check, other people's code might too. I can fix the Google ones but not the other ones. I'm just not feeling that this is a worthwhile check to make now, even though (as I said) I completely agree that it would have made sense if it had always been present.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this stricter validation be considered for a future version again? As pointed out above, most likely all cases where a
TypeToken
captures a type variable are not safe, potentially in very subtle ways.Just recently two Stack Overflow questions were created where the author stumbled exactly over this issue: