dotnet / runtime

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

Custom JsonConverter breaks context variable in JsonSchemaExporterOptions.TransformSchemaNode callback #109868

Open Peter-B- opened 2 hours ago

Peter-B- commented 2 hours ago

Description

I expect JsonSchemaExporterOptions.TransformSchemaNode to be invoked once for each property of a class. The JsonSchemaExporterContext parameter should be set to the property.

When I add a custom JsonConverter to multiple properties, only the callback for the last property is invoked. It is invoked for each property with a custom JsonConverter.

Reproduction Steps

Types

[JsonConverter(typeof(C1JsonConverter))]
public class C1 { }

[JsonConverter(typeof(C2JsonConverter))]
public class C2 { }

public class Test
{
    public C1 C1 { get; set; }
    public C2 C2 { get; set; }
}

Converters

public class C1JsonConverter:JsonConverter<C1>
{
    public override C1? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => 
        new();

    public override void Write(Utf8JsonWriter writer, C1 value, JsonSerializerOptions options) => 
        writer.WriteStringValue("C1");
}

public class C2JsonConverter:JsonConverter<C2>
{
    public override C2? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => 
        new();

    public override void Write(Utf8JsonWriter writer, C2 value, JsonSerializerOptions options) => 
        writer.WriteStringValue("C2");
}

Main

JsonSchemaExporterOptions exporterOptions = new()
{
    TransformSchemaNode = (context, schema) =>
    {
        Console.WriteLine($"Transform {context.TypeInfo.Type.Name} as {context.PropertyInfo?.Name}");

        return schema;
    }
};

var schema = JsonSerializerOptions.Web.GetJsonSchemaAsNode(typeof(Test), exporterOptions);
Console.WriteLine();
Console.WriteLine(schema.ToString());
Console.WriteLine();

Expected behavior

I expect to see one console message for each property:

Transform C1 as c1
Transform C2 as c2
Transform Test as

Actual behavior

The callback is invoked two times with the context of property Test.C2:

Transform C2 as c2
Transform C2 as c2
Transform Test as

Removing one or both of the custom JsonConverters will fix this issue.

Regression?

No response

Known Workarounds

No response

Configuration

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net9.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

</Project>

Other information

No response

dotnet-policy-service[bot] commented 2 hours ago

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