-
-
Notifications
You must be signed in to change notification settings - Fork 4
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
Restore polymorphism for JSON serialization #1039
Comments
@eiriktsarpalis I just tried this out 1152660 but it didn't work. Should this work, or is it just that the name of the property doesn't describe that it only works in the root of the JSON document? In essence I'm trying to do polymorphism of a property that is a child of the root: {
"foo": "bar",
"payload": {
"id": "whatever",
"type": "a type",
"...": "..."
}
} If this scenario isn't supported I'll just revert the changes, but if it should let me know and I'll open an issue in dotnet/runtime. |
Forgot the exception message from the logs:
|
You're right that the discriminator should be present at the same level as the type being serialized. Nested properties are not supported currently, sorry! |
I'm surprised that this message appears when out-of-order reads are enabled. Can you share a repro? |
The code in commit 1152660 should do it, but I could only find the issue by deploying it to AWS Lambda and then running my end-to-end test suite. The application is compiled with AoT, so that might be making the difference. I do have some tests here that should have found the issue before I even pushed the commit, but clearly I'm missing something here as they pass locally and in CI (where they aren't AOT'd). |
That is surprising. Would it be possible to file a minimal repro in the runtime repo? Thanks! |
Sure - I'll try and come up with something. |
Haven't started on the repro yet, but I did have a thought - if this isn't supported, why does my unit test work... 🤔 |
Right, I think I've worked out what's going on here:
If I change my code to provide a customization delegate for their options, then the polymorphism works as expected: - var serializer = new SourceGeneratorLambdaJsonSerializer<AppJsonSerializerContext>();
+ var serializer = new SourceGeneratorLambdaJsonSerializer<AppJsonSerializerContext>((p) => p.AllowOutOfOrderMetadataProperties = true); My end-to-end tests still fail, but that's because now I'm seeing a different AoT/trimmer related issue to do with Polly and/or HTTP resilience I need to investigate further, but it's resolved the JSON deserialization issue. My hunch as to why this discrepancy isn't being found and surfaced in an intuitive way ("I've set the thing but it's saying I haven't set the thing") is because This seems to raise the following questions:
|
Settings specified on the
I wouldn't say that's related. What this method does effectively is check if the particular run time configuration ends up invalidating the fast-path methods that were generated at compile time. Polymorphism isn't supported in fast path, so adding that check isn't necessary. |
Any suggestions on these two points? Ideally I'd have found this issue locally in my tests, rather than needing to wait for deployment to prod with AoT. Also if this is working "by accident", I'd likely revert the changes in case it suddenly breaks. |
I don't know. I would suggest creating a minimal repro, submitting it to the AWS team and we can take it from there.
Polymorphism will work for any value declared as polymorphic within the object graph. What isn't supported is nesting the type discriminator beneath the depth of the JSON object currently being serialized. |
That's the bit I'm still not getting - the type discriminator is at
|
Something else must be at play in that case. Here's how a vanilla example behaves: Console.WriteLine(JsonSerializer.Deserialize<MyPoco>("""{"type":"derived"}""") is DerivedPoco); // True
Console.WriteLine(JsonSerializer.Deserialize<MyPoco>("""{"request":{"type":"derived"}}""") is DerivedPoco); // False
[JsonPolymorphic(TypeDiscriminatorPropertyName = "type")]
[JsonDerivedType(typeof(DerivedPoco), "derived")]
class MyPoco;
class DerivedPoco : MyPoco; Unless of course by working in this case you mean that it's deserializing successfully even though it is an instance of the base type? That's by design, possible workarounds are to either specify a type discriminator for the base type itself or just mark the base type as abstract: Console.WriteLine(JsonSerializer.Deserialize<MyPoco>("""{"type":"derived"}""") is DerivedPoco); // True
Console.WriteLine(JsonSerializer.Deserialize<MyPoco>("""{"request":{"type":"derived"}}""") is DerivedPoco); // NotSupportedException
[JsonPolymorphic(TypeDiscriminatorPropertyName = "type")]
[JsonDerivedType(typeof(DerivedPoco), "derived")]
abstract class MyPoco;
class DerivedPoco : MyPoco; |
Ah I understand now - I misunderstood that what you meant was that polymorphism only works at the root, but what you're actually saying is that you can't have an object be polymorphic based on a property in a child property of that element. That's not what I'm doing in my case. I have something like this: public class Root
{
public Child Child { get; set; }
}
[JsonDerivedType(typeof(ChildA), "a")]
[JsonDerivedType(typeof(ChildB), "b")]
[JsonPolymorphic(TypeDiscriminatorPropertyName = "type")]
public abstract class Child
{
public string Name { get; set; }
}
public class ChildA : Child
{
public string SomeProperty { get; set; }
}
public class ChildB : Child
{
public string OtherProperty { get; set; }
} {
"child": {
"name": "some-name",
"type": "a",
"someProperty": "foo"
}
} {
"child": {
"name": "other-name",
"type": "b",
"otherProperty": "bar"
}
} Essentially I'm being polymorphic below the root, but for the child properties that are polymorphic, the type discriminator is at the same level as that property's properties. This is working as expected for me with the out-of-order support as I can deserialize the JSON document string to a That means now that I just need to figure out why I can't replicate the issue I was having that I fixed in 3bd0d0e locally. |
Mystery solved - my test payloads have the type discriminator as the first property (I think I just copied them from another source originally and modified them to be project specific), hence they never needed the out-of-order support and worked as-is. The payloads at runtime in AWS Lambda don't have it as the first (in the one I looked at just now it was third), hence the original blocker. 🤦 Migration successful then! |
JSON serialization polymorphism was removed in 83eb76f because it isn't supported by System.Text.Json.
It should be supported in .NET 9 preview 2, so once that's available in March(?) can try it out and see if it does the job.
See dotnet/runtime#72604 (comment).
The text was updated successfully, but these errors were encountered: