-
Notifications
You must be signed in to change notification settings - Fork 0
Make contexts more combinator friendly #9
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -55,9 +55,12 @@ public sealed partial class JsonSerializerOptions | |||||
| return converter; | ||||||
| } | ||||||
|
|
||||||
| /// <summary> | ||||||
| /// Gets converter for type but does not use TypeInfoResolver | ||||||
| /// </summary> | ||||||
| internal JsonConverter GetConverterForType(Type typeToConvert) | ||||||
| { | ||||||
| JsonConverter converter = GetConverterInternal(typeToConvert); | ||||||
| JsonConverter converter = GetConverterFromOptionsOrReflectionConverter(typeToConvert); | ||||||
| Debug.Assert(converter != null); | ||||||
|
|
||||||
| converter = ExpandFactoryConverter(converter, typeToConvert); | ||||||
|
|
@@ -122,39 +125,67 @@ public JsonConverter GetConverter(Type typeToConvert) | |||||
| } | ||||||
|
|
||||||
| DefaultJsonTypeInfoResolver.RootDefaultInstance(); | ||||||
| return GetConverterInternal(typeToConvert); | ||||||
| return GetConverterFromTypeInfo(typeToConvert); | ||||||
| } | ||||||
|
|
||||||
| internal JsonConverter GetConverterInternal(Type typeToConvert) | ||||||
| /// <summary> | ||||||
| /// Same as GetConverter but does not root converters | ||||||
| /// </summary> | ||||||
| internal JsonConverter GetConverterFromTypeInfo(Type typeToConvert) | ||||||
| { | ||||||
| // Only cache the value once (de)serialization has occurred since new converters can be added that may change the result. | ||||||
| if (_cachingContext != null) | ||||||
| if (_cachingContext == null) | ||||||
| { | ||||||
| return _cachingContext.GetOrAddConverter(typeToConvert); | ||||||
| if (_isLockedInstance) | ||||||
| { | ||||||
| InitializeCachingContext(); | ||||||
krwq marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
| } | ||||||
| else | ||||||
| { | ||||||
| // We do not want to lock options instance here but we need to return correct answer | ||||||
| // which means we need to go through TypeInfoResolver but without caching because that's the | ||||||
| // only place which will have correct converter for JsonSerializerContext and reflection | ||||||
| // based resolver. It will also work correctly for combined resolvers. | ||||||
| return GetTypeInfoInternal(typeToConvert)?.Converter | ||||||
| ?? GetConverterFromOptionsOrReflectionConverter(typeToConvert); | ||||||
|
|
||||||
| } | ||||||
| } | ||||||
|
|
||||||
| return GetConverterFromType(typeToConvert); | ||||||
| } | ||||||
| JsonConverter? converter = _cachingContext.GetOrAddJsonTypeInfo(typeToConvert)?.Converter; | ||||||
|
|
||||||
| internal JsonConverter GetConverterFromType(Type typeToConvert) | ||||||
| { | ||||||
| Debug.Assert(typeToConvert != null); | ||||||
| // we can get here if resolver returned null but converter was added for the type | ||||||
| converter ??= GetConverterFromOptions(typeToConvert); | ||||||
|
|
||||||
| // Priority 1: If there is a JsonSerializerContext, fetch the converter from there. | ||||||
| JsonConverter? converter = SerializerContext?.GetTypeInfo(typeToConvert)?.Converter; | ||||||
| if (converter == null) | ||||||
| { | ||||||
| ThrowHelper.ThrowNotSupportedException_BuiltInConvertersNotRooted(typeToConvert); | ||||||
|
||||||
| return null!; | ||||||
| } | ||||||
|
|
||||||
| return converter; | ||||||
| } | ||||||
|
|
||||||
| // Priority 2: Attempt to get custom converter added at runtime. | ||||||
| // Currently there is not a way at runtime to override the [JsonConverter] when applied to a property. | ||||||
| private JsonConverter? GetConverterFromOptions(Type typeToConvert) | ||||||
|
||||||
| { | ||||||
| foreach (JsonConverter item in _converters) | ||||||
| { | ||||||
| if (item.CanConvert(typeToConvert)) | ||||||
| { | ||||||
| converter = item; | ||||||
| break; | ||||||
| return item; | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| // Priority 3: Attempt to get converter from [JsonConverter] on the type being converted. | ||||||
| return null; | ||||||
| } | ||||||
|
|
||||||
| private JsonConverter GetConverterFromOptionsOrReflectionConverter(Type typeToConvert) | ||||||
|
||||||
| private JsonConverter GetConverterFromOptionsOrReflectionConverter(Type typeToConvert) | |
| private JsonConverter ResolveConverter(Type typeToConvert) |
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 actually isn't resolving converter - this is technically speaking reflection converter logic. From user perspective the order is following:
- type info converter (i.e. serializer context)
- options
- reflection converter (if rooted, if GetConverter called explicitly then this is always rooted)
this method does the last two and it's used by: reflection json type info and as a fallback for GetConverter (the fallback is arguably wrong but since we already shipped like that this logic is preserved here)
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 actually isn't resolving converter
Arguably it's resolving a converter based on the Converters list and the built-in stuff. My only concern is that we have accumulated too many JsonSerializer.GetConverter* method names and it might be in our interest to adopt a separate naming convention for the converter resolution logic that doesn't involve the cache in any way.
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.
There are only two case which must not use cache and first one could also cause stack overflow: reflection/custom type info resolver which needs to get converter; calling GetConverter before options are locked (caching cannot happen because converters/type infos can still be changed). Everything else is should go through caching
Uh oh!
There was an error while loading. Please reload this page.