-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
Fix JSON required read-only properties used as parametrized ctor #78152
Conversation
Tagging subscribers to this area: @dotnet/area-system-text-json, @gregsdennis Issue DetailsFixes: #78098 Consider for servicing because it makes properties without setter not usable with new
|
// Check for misuse of required properties | ||
// Ideally this check should be done during property.EnsureConfigured but at that point we have no knowledge about parametrized constructors | ||
// and we cannot check if property is read-only correctly | ||
foreach (KeyValuePair<string, JsonPropertyInfo> jsonPropertyInfoKv in PropertyCache.List) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this check could be moved inside the InitializePropertyCache
method to avoid iterating over the items yet again.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately not in current state because we initialize constructor parameter cache after InitializePropertyCache is called which means we can't check for that correctly in here because we don't know which ones are initialized as part parametrized constructor. It would need likely quite a bit of refactoring to move this logic - probably makes more sense to do that refactoring as part of adding parametrized constructors to the public contract.
foreach (KeyValuePair<string, JsonPropertyInfo> jsonPropertyInfoKv in PropertyCache.List) | ||
{ | ||
JsonPropertyInfo jsonPropertyInfo = jsonPropertyInfoKv.Value; | ||
jsonPropertyInfo.CheckRequiredPropertyIsMisused(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then this check could be moved inside JsonPropertyInfo.Configure with all the other propertyInfo-level validations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as I mentioned here: #78152 (comment) unfortunately that can't be move (at least not in the current state of the code), the ordering is following and each step depends on the previous:
- we initialize properties
- we initialize ctor parameters
- we check required properties used correctly
if I moved last step to first one we wouldn't know about which property is constructor parameter and be back to original bug
/// This property is modified after property's Configure but before its parent's JsonTypeInfo Configure is finished. | ||
/// This is due to parameterized constructor logic needing propeties to be Configured. | ||
/// </remarks> | ||
internal bool IsWritable => CanDeserialize || IsConstructorParameter; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IsWritable
sounds kind of ambiguous when compared with CanDeserialize
. Given that it's only being called in one place I think you could simply inline CanDeserialize || IsConstructorParameter
to make it more clear what is being checked?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I initially done it this way but I ended up splitting it because I eventually want to fix #77307 which will need similar property.
@@ -264,6 +282,12 @@ internal static JsonPropertyInfo GetPropertyPlaceholder() | |||
/// </summary> | |||
public Type PropertyType { get; } | |||
|
|||
internal void MarkAsConstructorParameter() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really need this method? IsConstructorParameter
has a private setter so we can assume that the assert invariant is preserved.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is called from JsonTypeInfo.CreateConstructorParameter - I prefer to have it here rather than making IsConstructorParameter
internal - this way I can add extra check and make sure it's not going to be misused in the future.
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonPropertyInfo.cs
Outdated
Show resolved
Hide resolved
Per feedback in #78098 (comment), I don't think this meets the bar for servicing. I'm not entirely convinced that we should be supporting That being said, there clearly is a gap in functionality when it comes to specifying required constructor parameters (currently, STJ will pass We also need to be careful about what the relationship between |
@krwq please do not add |
@krwq I'm putting this into Draft status since it's accumulated some merge conflicts and it might be easier to start with a fresh PR when we return to this. |
Draft Pull Request was automatically closed for 30 days of inactivity. Please let us know if you'd like to reopen it. |
Reopen? :) |
I'll focus on this PR after #78556 |
@krwq should we close this? We can revisit constructor parameters overall in the next release. |
Yeah, let's go ahead and close it for revisiting in net9. |
Fixes: #78098
Fixes following scenario: