Skip to content

Serializing source-generated nullable init-only properties throws when using RespectNullableAnnotations #107968

@jupjohn

Description

@jupjohn

Description

When serializing a null JSON property against a nullable init-only class property using a source generated JsonSerializerContext with RespectNullableAnnotations enabled, the serializer throws and exception claiming that the property doesn't allow null values.

This behaviour is not present when using a runtime type serializer instead of a source-generated one.

Reproduction Steps

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

const string jsonObject =
    """
    {
        "NullableProperty": null
    }
    """;

var result = JsonSerializer.Deserialize(jsonObject, NullableJsonContext.Default.MyNullableObject);
Console.WriteLine(result!.NullableProperty);


public class MyNullableObject
{
    public string? NullableProperty { get; init; }
}

// Setting RespectNullableAnnotations to false will make this pass, as will changing the init accessor to a private setter
[JsonSourceGenerationOptions(RespectNullableAnnotations = true)]
[JsonSerializable(typeof(MyNullableObject))]
public partial class NullableJsonContext : JsonSerializerContext;

Expected behavior

The nullable property (NullableProperty in the example) serializes the property as a null value.

Actual behavior

Serialization throws a JsonException:

Unhandled exception. System.Text.Json.JsonException: The constructor parameter 'NullableProperty' on type 'MyNullableObject' doesn't allow null values. Consider updating its nullability annotation. Path: $.NullableProperty | LineNumber: 1 | BytePositionInLine: 28.
   at System.Text.Json.ThrowHelper.ThrowJsonException_ConstructorParameterDisallowNull(String parameterName, Type declaringType)
   at System.Text.Json.Serialization.Converters.LargeObjectWithParameterizedConstructorConverter`1.ReadAndCacheConstructorArgument(ReadStack& state, Utf8JsonReader& reader, JsonParameterInfo jsonParameterInfo)
   at System.Text.Json.Serialization.Converters.ObjectWithParameterizedConstructorConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
   at System.Text.Json.Serialization.Converters.JsonMetadataServicesConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
   at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value, Boolean& isPopulatedValue)
   at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, T& value, JsonSerializerOptions options, ReadStack& state)
   at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.Deserialize(Utf8JsonReader& reader, ReadStack& state)
   at System.Text.Json.JsonSerializer.ReadFromSpan[TValue](ReadOnlySpan`1 utf8Json, JsonTypeInfo`1 jsonTypeInfo, Nullable`1 actualByteCount)
   at System.Text.Json.JsonSerializer.ReadFromSpan[TValue](ReadOnlySpan`1 json, JsonTypeInfo`1 jsonTypeInfo)
   at System.Text.Json.JsonSerializer.Deserialize[TValue](String json, JsonTypeInfo`1 jsonTypeInfo)
   at Program.<Main>$(String[] args) in /.../Program.cs:line 11

Regression?

No response

Known Workarounds

Using a non-source generated serializer works:

JsonSerializer.Deserialize<MyNullableObject>(jsonObject);

Configuration

Tested on:

  • .NET 8
  • System.Text.Json 9.0.0-rc.1.24431.7
  • Windows & Linux
  • x64
  • Platform/arch independent

Other information

No response

Metadata

Metadata

Labels

area-System.Text.Jsonbugin-prThere is an active PR which will close this issue when it is merged

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions