-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Assign PropertyCache after it's configured for source gen in attempt to fix JSON LookupProperty assert failing #68480
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -220,19 +220,23 @@ internal virtual void Configure() | |
// also assigns JsonPropertyInfo's JsonTypeInfo which causes SO if there are any | ||
// cycles in the object graph. For that reason properties cannot be added immediately. | ||
// This is a no-op for ReflectionJsonTypeInfo | ||
LateAddProperties(); | ||
var propertyCache = LateAddProperties() ?? PropertyCache; | ||
|
||
DataExtensionProperty?.EnsureConfigured(); | ||
|
||
if (converter.ConverterStrategy == ConverterStrategy.Object && PropertyCache != null) | ||
if (converter.ConverterStrategy == ConverterStrategy.Object && propertyCache != null) | ||
{ | ||
foreach (var jsonPropertyInfoKv in PropertyCache.List) | ||
foreach (var jsonPropertyInfoKv in propertyCache.List) | ||
{ | ||
JsonPropertyInfo jsonPropertyInfo = jsonPropertyInfoKv.Value!; | ||
jsonPropertyInfo.DeclaringTypeNumberHandling = NumberHandling; | ||
jsonPropertyInfo.EnsureConfigured(); | ||
} | ||
|
||
// This code can be run in multiple threads therefore we assign only after all properties has been configured | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this change makes the code more complicated without addressing the core issue, which is described in the comment here. It doesn't fix all potential race conditions hiding in the initialization code, nor does it prevent any future races from being introduced as the code gets changed. The only real solution is to prevent multiple threads from attempting to write to an instance. There are a few approaches we could pursue longer term, but the immediate need is to unblock CI for others. As an interim solution I would recommend adding a double-checked lock in the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was hoping we could achieve same without having to do locks but agreed it will make it harder to prevent from the regression to happen again. Will revert and lock There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. actually let me close this PR and create a new one since it's effectively different change |
||
// This only matters in case we call LateAddProperties | ||
PropertyCache = propertyCache; | ||
|
||
if (converter.ConstructorIsParameterized) | ||
{ | ||
InitializeConstructorParameters(GetParameterInfoValues(), sourceGenMode: Options.JsonSerializerContext != null); | ||
|
@@ -280,7 +284,7 @@ internal string GetDebugInfo() | |
} | ||
#endif | ||
|
||
internal virtual void LateAddProperties() { } | ||
internal virtual JsonPropertyDictionary<JsonPropertyInfo>? LateAddProperties() { return null; } | ||
|
||
internal virtual JsonParameterInfoValues[] GetParameterInfoValues() | ||
{ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -92,9 +92,9 @@ private static JsonConverter GetConverter(JsonCollectionInfoValues<T> collection | |
return new JsonMetadataServicesConverter<T>(converterCreator, strategy); | ||
} | ||
|
||
internal override void LateAddProperties() | ||
internal override JsonPropertyDictionary<JsonPropertyInfo>? LateAddProperties() | ||
{ | ||
AddPropertiesUsingSourceGenInfo(); | ||
return AddPropertiesUsingSourceGenInfo(); | ||
} | ||
|
||
internal override JsonParameterInfoValues[] GetParameterInfoValues() | ||
|
@@ -110,11 +110,11 @@ internal override JsonParameterInfoValues[] GetParameterInfoValues() | |
return array; | ||
} | ||
|
||
internal void AddPropertiesUsingSourceGenInfo() | ||
internal JsonPropertyDictionary<JsonPropertyInfo>? AddPropertiesUsingSourceGenInfo() | ||
{ | ||
if (PropertyInfoForTypeInfo.ConverterStrategy != ConverterStrategy.Object) | ||
{ | ||
return; | ||
return null; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we also exit early for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. likely yes but I'd prefer to keep those changes separate |
||
} | ||
|
||
JsonSerializerContext? context = Options.JsonSerializerContext; | ||
|
@@ -123,23 +123,23 @@ internal void AddPropertiesUsingSourceGenInfo() | |
{ | ||
if (typeof(T) == typeof(object)) | ||
{ | ||
return; | ||
return null; | ||
} | ||
|
||
if (PropertyInfoForTypeInfo.ConverterBase.ElementType != null) | ||
{ | ||
// Nullable<> or F# optional converter's strategy is set to element's strategy | ||
return; | ||
return null; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are there some There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This specific check is happening because There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It only will report |
||
} | ||
|
||
if (SerializeHandler != null && Options.JsonSerializerContext?.CanUseSerializationLogic == true) | ||
{ | ||
ThrowOnDeserialize = true; | ||
return; | ||
return null; | ||
} | ||
|
||
ThrowHelper.ThrowInvalidOperationException_NoMetadataForTypeProperties(context, Type); | ||
return; | ||
return null; | ||
} | ||
|
||
Dictionary<string, JsonPropertyInfo>? ignoredMembers = null; | ||
|
@@ -179,7 +179,7 @@ internal void AddPropertiesUsingSourceGenInfo() | |
CacheMember(jsonPropertyInfo, propertyCache, ref ignoredMembers); | ||
} | ||
|
||
PropertyCache = propertyCache; | ||
return propertyCache; | ||
} | ||
|
||
private void SetCreateObjectFunc(Func<T>? createObjectFunc) | ||
|
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.
nit: should the declaring type's
NumberHandling
be passed toEnsureConfigured()
as an argument?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.
more likely
this
(declaring type JsonTypeInfo) perhaps because we don't really know if other info might be needed here. I'll refrain from changing it in this PR