-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
[ClientRuntime] Fixed polymorphic deserialization #3503
[ClientRuntime] Fixed polymorphic deserialization #3503
Conversation
7e53f43
to
787d060
Compare
@shahabhijeet any clue why CI no longer terminates? It actually is hanging up on the CR tests, so it must be my change. Could it be the fact that I'm using reflection? WTF. |
@olydis looking at the logs it is not clear at all as to why the test process was terminated. |
var json = JsonConvert.SerializeObject(instance, SerializeJsonConverter); | ||
return JsonConvert.DeserializeObject<T>(json, DeserializeJsonConverter); | ||
} | ||
private static void AssertRoundTrips<T>(T instance) where T : Model |
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.
@olydis do we have any negative tests, where it fails to convert if we reverse the order of inheritance hierarchy? If not we should add those.
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.
will add
@shahabhijeet well, it says timeout, but I don't get how my test times out on both Linux and Windows... will try to repro locally, but it definitely ran through on my machine before 😞 |
9bc82ab
to
06c2225
Compare
@shahabhijeet investigating the non-termination I exposed an even more fundamental issue... my fix will have to be more sophisticated 😉 |
f0423e8
to
2008a09
Compare
@markcowl @shahabhijeet Note that I had to essentially rewrite the deserializer from scratch, it was very fundamentally broken, I'll gladly share details. In short: Calling My current approach explicitly traverses down into the properties before calling out to Newtonsoft.JSON again. |
bbf65c2
to
fbcf230
Compare
886bbed
to
5799ae4
Compare
…xperience even when calling one of the RPs scripts)
5799ae4
to
d26f0e5
Compare
ca2d946
to
ae3ab89
Compare
@shahabhijeet MachineLearning tests with the weird boolean toggle problem (that I really couldn't connect to polymorphic deserialization) pass now! All I did was rebase onto your most recent changes in |
* reproing test (deep hiararchy) * reproing test (base class property) * fix * bold move * tiny improvement to generate.cmd (just making sure you get the same experience even when calling one of the RPs scripts) * case insensitive property lookup (I guess we're already down that rabbit hole) * tiny improvement to generate.cmd (mention commit IDs, clarifications) * tiny improvement to generateMetadata.cmd (handle commit IDs)
Issue 1 (see 1st commit for repro): Multi-level inheritance
Happens when
<static type of property> != <base type> && <static type of property> != <leaf type> && <dynamic type of property> == <leaf type>
Then
<dynamic type of property> != <leaf type>
after round trip.Description
Polymorphic deserialization has broken cases. Consider the following scenario:
An API method returning an
A
will callJsonConvert.DeserializeObject<A>(...response body...)
. ThePolymorphicDeserializeJsonConverter
we have will successfully deserialize objects of dynamic typeA
,B
andC
using the discriminator.Now, there may be another API method returning
B
. AutoRest will (reasonably) emitJsonConvert.DeserializeObject<B>(...response body...)
. Note that the service may return an object of dynamic typeB
orC
. However,PolymorphicDeserializeJsonConverter
will not be aware that it still applies so we will always deserialize intoB
!Summary
Current behavior:
PolymorphicDeserializeJsonConverter
only works correctly forJsonConvert.DeserializeObject<T>
whereT = <root type>
(the root type is the type that thediscriminator
was declared on)Expected behavior:
PolymorphicDeserializeJsonConverter
works correctly forJsonConvert.DeserializeObject<T>
whereT : <root type>
, i.e.T
is any type in the inheritance hierarchy.Note that this problem is only exposed for hierarchies of depth at least 2 since otherwise you are dealing with either the root type (which the converter works fine for) or a leaf type (which works fine natively).
Related issue: Azure/autorest#2430
Issue 2 (see 2nd commit for repro): Polymorphic property on base class of polymorphic hierarchy
Happens when
<static type of property's declaring class> == <base type> && <dynamic type of property's declaring class> == <base type> && <dynamic type of property> != <static type of property>
Then
<dynamic type of property> == <static type of property>
after round trip.Description
Consider the following scenario:
Then
Summary
When polymorphic types are deserialized and the base type is detected (above:
A
), the object is deserialized with the default deserializer, i.e. without passing along the polymorphic deserializer.As a result, any properties (transitively) of the object will be naively deserialized into their static types.
This checklist is used to make sure that common guidelines for a pull request are followed.
General Guidelines
Testing Guidelines