Skip to content

JsonIgnore attribute has no effect on init-only properties in source generation mode #101877

Closed
@trympet

Description

@trympet

Description

The JsonIgnore attribute is ignored for init-only properties in source generation mode.

A motivating example is when I have an outer record wrapping some inner record to perform some serialization transformation.

record MyRecord([property: JsonIgnore] MyOtherRecord MyOtherRecord)
{
    [JsonConstructor]
    public MyRecord(int foo) : this(new MyOtherRecord(foo, "Baz"))
    {
    }

    [JsonPropertyName("foo")] public string Foo => MyOtherRecord.Foo.ToString();
}

record MyOtherRecord(int Foo, string Bar);

[JsonSerializable(typeof(MyRecord))]
partial class JsonContext : JsonSerializerContext;

In the example above, the object initializer for MyRecord, generated by the json source generation machinery, would override the initialized value of the MyOtherRecord property to null -- despite having a JsonIgnore applied to the property.

Reproduction Steps

Apply the JsonIgnore attribute to an init-only property and observe that the init is invoked upon object construction. As illustrated below, the behavior seems to diverge from reflection mode.

var reflection = JsonSerializer.Deserialize<JsonClass>("""{"A":1}""");
Console.WriteLine($"Property: {reflection!.Property}"); // Property: 42

var sourceGenerated = JsonSerializer.Deserialize<JsonClass>("""{"A":1}""", JsonContext.Default.JsonClass);
Console.WriteLine($"Property: {sourceGenerated!.Property}"); // Property: 0

class JsonClass
{
    [JsonIgnore(Condition = JsonIgnoreCondition.Always)]
    public int Property { get; init; } = 42;
}

[JsonSerializable(typeof(JsonClass))]
partial class JsonContext : JsonSerializerContext;

Expected behavior

The JsonIgnore attribute should, when applied to an init-only property, cause the property initializer to be omitted entirely from object construction.

From the docs:

[JsonIgnore] Prevents a property or field from being serialized or deserialized.

Actual behavior

The init-only property is effectively behaving as if the ignore condition is set to JsonIgnoreCondition.Never, thus causing any value set in the constructor to subsequently be overridden.

Regression?

No response

Known Workarounds

Changing the accessor from init to set updates ObjectWithParameterizedConstructorCreator from static args => new global::JsonClass(){ Property = (int)args[0] } to static args => new global::JsonClass().

Configuration

.NET 8
SDK 8.0.204

Other information

No response

Metadata

Metadata

Labels

area-System.Text.Jsonbugin-prThere is an active PR which will close this issue when it is mergedsource-generatorIndicates an issue with a source generator feature

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions