-
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
System.Text.Json POCOs with constructor deserialization doesn't support metadata reads ($ref) #73302
Comments
Tagging subscribers to this area: @dotnet/area-system-text-json, @gregsdennis Issue DetailsDescriptionI'm trying to deserialize some JSON that references other objects but it fails to do so. I have the following configuration (only for the ReferenceHandler) internal static readonly JsonSerializerOptions DefaultOptions = new()
{
WriteIndented = true,
ReferenceHandler = ReferenceHandler.Preserve
}; But when trying to deserialize the JSON, it fails with the following exception:
I assume this issue is caused for the same reason as #66604 which attempted to be fixed in #67183. I had the issue with other objects with the field Below is a working reproduction code. Reproduction StepsThe following code breaks: // See https://aka.ms/new-console-template for more information
using System.Text.Json;
using System.Text.Json.Serialization;
var exampleA = new ExampleA("Xyz")
{
Bs = new HashSet<ExampleB>()
};
exampleA.Bs.Add(new ExampleB("Abc")
{
A = exampleA
});
var options = new JsonSerializerOptions
{
ReferenceHandler = ReferenceHandler.Preserve
};
var json = JsonSerializer.Serialize(exampleA, options);
exampleA = JsonSerializer.Deserialize<ExampleA>(json, options);
Console.WriteLine("Done.");
public class ExampleA
{
public ISet<ExampleB> Bs { get; set; }
public string Test { get; set; }
public ExampleA(string test)
{
Test = test;
}
}
public class ExampleB
{
public ExampleA A { get; set; }
public string Test { get; set; }
public ExampleB(string test)
{
Test = test;
}
} The following code works: // See https://aka.ms/new-console-template for more information
using System.Text.Json;
using System.Text.Json.Serialization;
var exampleA = new ExampleA
{
Bs = new HashSet<ExampleB>(),
Test = "Xyz"
};
exampleA.Bs.Add(new ExampleB
{
A = exampleA,
Test = "Abc"
});
var options = new JsonSerializerOptions
{
ReferenceHandler = ReferenceHandler.Preserve
};
var json = JsonSerializer.Serialize(exampleA, options);
exampleA = JsonSerializer.Deserialize<ExampleA>(json, options);
Console.WriteLine("Done.");
public class ExampleA
{
public ISet<ExampleB> Bs { get; set; }
public string Test { get; set; }
}
public class ExampleB
{
public ExampleA A { get; set; }
public string Test { get; set; }
} Expected behaviorDeserialization happens properly even when there's a constructor. Actual behaviorDeserialization can't happen because it says it's not supported even though it should be? Regression?No response Known WorkaroundsThe only workaround in my case is to remove the constructors of my classes and use Configuration.NET 6 (6.0.302) Other informationNo response
|
This is a known limitation. Ultimately, it is not possible to implement correctly out of bootstrapping concerns: constructor parameters must be deserialized before the current value can be instantiated. As such, it becomes impossible to deserialize values like the following: JsonSerializer.Deserialize<Person>("""{ "$id" : "1", "parent" : { "$ref" : "1"} }""");
public record Person(Person? parent); Even though not all reference preservation scenaria contain cycles, it arguably is the raison d'etre of the feature. While we could try to make the feature smarter and only fail if cycles are detected, this would require substantially more state to track correctly and it would impact performance. Consequently, explicitly not supporting the feature at all for constructor deserialization is the right apprioach in my view. As you mention, the workaround is to simply refactor constructor parameters to be |
Description
I'm trying to deserialize some JSON that references other objects but it fails to do so.
I have the following configuration (only for the ReferenceHandler)
But when trying to deserialize the JSON, it fails with the following exception:
I assume this issue is caused for the same reason as #66604 which attempted to be fixed in #67183. I had the issue with other objects with the field
$id
causing the same exception, so I updated to7.0.0-preview.6.22324.4
which fixed the issue.Below is a working reproduction code.
Reproduction Steps
The following code breaks:
The following code works:
Expected behavior
Deserialization happens properly even when there's a constructor.
Actual behavior
Deserialization can't happen because it says it's not supported even though it should be?
Regression?
No response
Known Workarounds
The only workaround in my case is to remove the constructors of my classes and use
init-only
properties but I'd like to not do this.Configuration
.NET 6 (6.0.302)
Windows 11 (Version 21H2 (OS Build 22000.795))
x64
Other information
No response
The text was updated successfully, but these errors were encountered: