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

Use native NullabilityInfoContext #1167

Closed
wants to merge 5 commits into from
Closed

Conversation

maurei
Copy link
Member

@maurei maurei commented Jul 5, 2022

Use the native NullabilityInfoContext for checking on nullability information rather than relying on Swashbuckles work-around.

@maurei maurei changed the base branch from master to openapi July 5, 2022 23:19
@maurei maurei requested a review from bkoelman July 5, 2022 23:22
@maurei maurei marked this pull request as ready for review July 5, 2022 23:41
@codecov
Copy link

codecov bot commented Jul 6, 2022

Codecov Report

Merging #1167 (0cc59db) into openapi (f65b7fe) will increase coverage by 0.03%.
The diff coverage is 100.00%.

❗ Current head 0cc59db differs from pull request most recent head 49f9ff2. Consider uploading reports for the commit 49f9ff2 to get more accurate results

@@             Coverage Diff             @@
##           openapi    #1167      +/-   ##
===========================================
+ Coverage    92.24%   92.27%   +0.03%     
===========================================
  Files          302      301       -1     
  Lines         8768     8756      -12     
===========================================
- Hits          8088     8080       -8     
+ Misses         680      676       -4     
Impacted Files Coverage Δ
...ApiDotNetCore.OpenApi/JsonApiObjects/SingleData.cs 0.00% <ø> (ø)
...etCore.OpenApi/ResourceFieldAttributeExtensions.cs 100.00% <100.00%> (+12.50%) ⬆️
...penApi/SwaggerComponents/JsonApiSchemaGenerator.cs 98.36% <100.00%> (+0.02%) ⬆️
...ggerComponents/ResourceFieldObjectSchemaBuilder.cs 98.97% <100.00%> (+1.02%) ⬆️
...NetCore/Repositories/ResourceRepositoryAccessor.cs 100.00% <100.00%> (ø)

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

Copy link
Member

@bkoelman bkoelman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm in favor of relying on NullabilityInfoContext eventually, but I think tests should be part of this PR to ensure correctness today.

Resolving the nullability state turns out to be quite complicated when generics are involved. And I found that .NET 6 contains quite some bugs, which were recently fixed for .NET 7.

For example, simple cases like the following fail to produce the correct result on .NET 6:

#nullable enable
class Customer : Identifiable<string>
{
}

PropertyInfo property = typeof(Customer).GetProperty("Id")!;
NullabilityInfoContext nullContext = new NullabilityInfoContext();
NullabilityInfo nullability = nullContext.Create(property);
Console.WriteLine(nullability.ReadState); // prints Nullable

};
NullabilityInfo nullabilityInfo = NullabilityInfoContext.Create(source.Property);

return nullabilityInfo.ReadState == NullabilityState.Nullable && !hasRequiredAttribute;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the first part should be nullabilityInfo.ReadState != NullabilityState.NotNull, to account for Unknown (NRT off)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unlike JsonApiSchemaGenerator.IsDataPropertyNullable, here properties can indeed live in types that have NRT disabled, so this is a bug. This slipped through because at this point there aren't any tests that check the behaviour for NRT disabled input. I have a PR lined up for #1111 where these scenarios are extensively tested

I agree that it would be better to have these test cases worked out extensively before changing this mechanism. I will put this PR on hold for now.


return typeCategory == TypeCategory.NullableReferenceType;
NullabilityInfo nullabilityInfo = NullabilityInfoContext.Create(dataProperty);
return nullabilityInfo.ReadState == NullabilityState.Nullable;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should probably be:

return nullabilityInfo.ReadState != NullabilityState.NotNull;

to handle the case where the state is Unknown (NRT off). Although I wonder if that situation can occur, assuming the Data property is defined inside JADNC.

Copy link
Member Author

@maurei maurei Jul 9, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although I wonder if that situation can occur, assuming the Data property is defined inside JADNC.

Correct! The nullability info of property it checks are within types that are internal to JADNC, where NRT is guaranteed to be enabled.

Upon looking at it again, however, I realised there is an even easier check we can perform. This resulted in removing this block code entirely.

@@ -224,6 +225,7 @@ private static bool IsDataPropertyNullable(Type type)
throw new UnreachableCodeException();
}

return dataProperty.GetTypeCategory() == TypeCategory.NullableReferenceType;
NullabilityInfo nullabilityInfo = NullabilityInfoContext.Create(dataProperty);
return nullabilityInfo.ReadState == NullabilityState.Nullable;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same remark as for JsonApiSchemaGenerator.IsDataPropertyNullable applies here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same answer applies as for JsonApiSchemaGenerator.IsDataPropertyNullable. The argument type is always a relationship schema type managed by JADNC.

where TData : ResourceIdentifierObject
// ReSharper disable once RedundantNotNullConstraint
// See ReSharper bug: https://youtrack.jetbrains.com/issue/RSRP-489137/False-positive-on-RedundantNotNullConstraint
where TData : notnull, ResourceIdentifierObject
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not seeing any tests fail when removing the notnull constraint. Why is it needed here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initially I had an implementation for JsonApiSchemaGenerator.IsDataPropertyNullable that did depend on this constraint being there. I did something similar to the bug report I did for ReSharper. However now these helper methods behave in an entirely different way, so no longer tests will fail.

Nevertheless, for completeness I figured it would be good to keep the constraints.

However, looking closely at this bug report, I wonder if this is really a bug report in ReSharper, or if ReSharper is actually right and it is a bug in net60.

@bkoelman bkoelman marked this pull request as draft August 21, 2022 15:02
@maurei maurei closed this Sep 6, 2022
@maurei maurei deleted the openapi-nullability-context branch September 6, 2022 15:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

2 participants