Skip to content
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

Schema of generic type: incorrect nullability #164

Open
Apollo3zehn opened this issue Feb 5, 2025 · 0 comments
Open

Schema of generic type: incorrect nullability #164

Apollo3zehn opened this issue Feb 5, 2025 · 0 comments

Comments

@Apollo3zehn
Copy link

I have the following setup to compare the schema of a non-generic type (A) to a generic version (A<B>) :

.csproj:

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

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

  <ItemGroup>
    <PackageReference Include="NJsonSchema" Version="11.0.2" />
  </ItemGroup>

</Project>

Program.cs:

using NJsonSchema;

var nonGenericSchema = JsonSchema.FromType<A>();
var genericSchema = JsonSchema.FromType<A<B>>();

Console.WriteLine("Non-generic schema:");
Console.WriteLine(nonGenericSchema.ToJson());

Console.WriteLine("\n\nGeneric schema:");
Console.WriteLine(genericSchema.ToJson());

public record A
(
    B B
);

public record A<T>
(
    T B
);

public record B(string Value);

Unfortunately, in the generic version, the property B becomes nullable although it is not so in the C# type definition. Here is a comparison of both schemas:

Output:

Non-generic schema:
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "title": "A",
  "type": "object",
  "additionalProperties": false,
  "properties": {
    "B": {
      "oneOf": [
        {
          "type": "null"
        },
        {
          "$ref": "#/definitions/B"
        }
      ]
    }
  },
  "definitions": {
    "B": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "Value": {
          "type": "string"
        }
      }
    }
  }
}


Generic schema:
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "title": "AOfB",
  "type": "object",
  "additionalProperties": false,
  "properties": {
    "B": {
      "oneOf": [
        {
          "type": "null"
        },
        {
          "$ref": "#/definitions/B"
        }
      ]
    }
  },
  "definitions": {
    "B": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "Value": {
          "type": "string"
        }
      }
    }
  }
}

I think the reason is that there is no customAttributeProviders provided in the following call:

return new ContextualType(type, contextualAttributeProvider ?? new GenericTypeContext(Array.Empty<Attribute>()), null, ref index, null, null);

When this parameter is null, the call to InitializeNullableFlagsAndOriginalNullability ends with _emptyNullableFlags.

There is a big difference between both call stacks (non-generic vs generic) and the generic one leads to a call to GetCachedType which in turn passes null for the customAttributeProviders parameter.

Image

I tried to debug it for hours (with a more complex type in the beginning) but I think more knowledge of the library internals is required to find the root cause. And I am not really sure if the bug is burried somewhere in this library or in NJsonSchema.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant