dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
14.91k stars 4.63k forks source link

`JsonObjectCreationHandling.Populate` handles init-only properties inconsistently in reflection/source gen #93114

Open eiriktsarpalis opened 11 months ago

eiriktsarpalis commented 11 months ago

Consider the following reproduction:

using System.Text.Json;
using System.Text.Json.Serialization;

string json = """{ "Nested" : { "Id" : "id" } }""";

MyPoco? result = JsonSerializer.Deserialize<MyPoco>(json);
Console.WriteLine(result!.Nested.Id); // "id"
result = JsonSerializer.Deserialize<MyPoco>(json, MyContext.Default.MyPoco);
Console.WriteLine(result!.Nested.Id); // System.InvalidOperationException: Setting init-only properties is not supported in source generation mode.

[JsonObjectCreationHandling(JsonObjectCreationHandling.Populate)]
public class MyPoco
{
    public NestedPoco Nested { get; } = new();
}

public class NestedPoco
{
    public string Id { get; init; } = "<null>";
}

[JsonSerializable(typeof(MyPoco))]
public partial class MyContext : JsonSerializerContext { }

This is most probably expected given the nature of init-only properties in source gen, but perhaps it would make sense to also fail in the case of the reflection serializer (since the current behavior violates the init contract of the nested poco).

ghost commented 11 months ago

Tagging subscribers to this area: @dotnet/area-system-text-json, @gregsdennis See info in area-owners.md if you want to be subscribed.

Issue Details
Consider the following reproduction: ```C# using System.Text.Json; using System.Text.Json.Serialization; string json = """{ "Nested" : { "Id" : "id" } }"""; MyPoco? result = JsonSerializer.Deserialize(json); Console.WriteLine(result!.Nested.Id); // "id" result = JsonSerializer.Deserialize(json, MyContext.Default.MyPoco); Console.WriteLine(result!.Nested.Id); // System.InvalidOperationException: Setting init-only properties is not supported in source generation mode. [JsonObjectCreationHandling(JsonObjectCreationHandling.Populate)] public class MyPoco { public NestedPoco Nested { get; } = new(); } public class NestedPoco { public string Id { get; init; } = ""; } [JsonSerializable(typeof(MyPoco))] public partial class MyContext : JsonSerializerContext { } ```
Author: eiriktsarpalis
Assignees: -
Labels: `area-System.Text.Json`, `untriaged`
Milestone: -
krwq commented 11 months ago

something to consider when fixing this: should reflection work when Nested is initially null?