Skip to content

Commit 0d679d0

Browse files
Address pending feedback and tidy up DefaultJsonTypeInfoResolver rooting logic.
1 parent d501ae1 commit 0d679d0

File tree

5 files changed

+47
-51
lines changed

5 files changed

+47
-51
lines changed

src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs

Lines changed: 9 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,7 @@ public static JsonSerializerOptions Default
4141
[RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
4242
get
4343
{
44-
if (s_defaultOptions is not JsonSerializerOptions options)
45-
{
46-
options = GetOrCreateDefaultOptionsInstance();
47-
}
48-
49-
return options;
44+
return s_defaultOptions ?? GetOrCreateSingleton(ref s_defaultOptions, JsonSerializerDefaults.General);
5045
}
5146
}
5247

@@ -66,12 +61,7 @@ public static JsonSerializerOptions Web
6661
[RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
6762
get
6863
{
69-
if (s_webOptions is not JsonSerializerOptions options)
70-
{
71-
options = GetOrCreateWebOptionsInstance();
72-
}
73-
74-
return options;
64+
return s_webOptions ?? GetOrCreateSingleton(ref s_webOptions, JsonSerializerDefaults.Web);
7565
}
7666
}
7767

@@ -777,7 +767,7 @@ private void ConfigureForJsonSerializer()
777767
{
778768
// Even if a resolver has already been specified, we need to root
779769
// the default resolver to gain access to the default converters.
780-
DefaultJsonTypeInfoResolver defaultResolver = DefaultJsonTypeInfoResolver.RootDefaultInstance();
770+
DefaultJsonTypeInfoResolver defaultResolver = DefaultJsonTypeInfoResolver.DefaultInstance;
781771

782772
switch (_typeInfoResolver)
783773
{
@@ -963,30 +953,24 @@ protected override void OnCollectionModifying()
963953

964954
[RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
965955
[RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
966-
private static JsonSerializerOptions GetOrCreateDefaultOptionsInstance()
956+
private static JsonSerializerOptions GetOrCreateSingleton(
957+
ref JsonSerializerOptions? location,
958+
JsonSerializerDefaults defaults)
967959
{
968-
var options = new JsonSerializerOptions
960+
var options = new JsonSerializerOptions(defaults)
969961
{
970962
// Because we're marking the default instance as read-only,
971963
// we need to specify a resolver instance for the case where
972964
// reflection is disabled by default: use one that returns null for all types.
973965

974966
TypeInfoResolver = JsonSerializer.IsReflectionEnabledByDefault
975-
? DefaultJsonTypeInfoResolver.RootDefaultInstance()
967+
? DefaultJsonTypeInfoResolver.DefaultInstance
976968
: JsonTypeInfoResolver.Empty,
977969

978970
_isReadOnly = true,
979971
};
980972

981-
return Interlocked.CompareExchange(ref s_defaultOptions, options, null) ?? options;
982-
}
983-
984-
[RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
985-
[RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
986-
private static JsonSerializerOptions GetOrCreateWebOptionsInstance()
987-
{
988-
var options = new JsonSerializerOptions(JsonSerializerDefaults.Web) { _isReadOnly = true };
989-
return Interlocked.CompareExchange(ref s_webOptions, options, null) ?? s_webOptions;
973+
return Interlocked.CompareExchange(ref location, options, null) ?? options;
990974
}
991975

992976
[DebuggerBrowsable(DebuggerBrowsableState.Never)]

src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/DefaultJsonTypeInfoResolver.Converters.cs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ public partial class DefaultJsonTypeInfoResolver
1919
[RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
2020
private static JsonConverterFactory[] GetDefaultFactoryConverters()
2121
{
22-
return new JsonConverterFactory[]
23-
{
22+
return
23+
[
2424
// Check for disallowed types.
2525
new UnsupportedTypeConverterFactory(),
2626
// Nullable converter should always be next since it forwards to any nullable type.
@@ -35,7 +35,7 @@ private static JsonConverterFactory[] GetDefaultFactoryConverters()
3535
new IEnumerableConverterFactory(),
3636
// Object should always be last since it converts any type.
3737
new ObjectConverterFactory()
38-
};
38+
];
3939
}
4040

4141
private static Dictionary<Type, JsonConverter> GetDefaultSimpleConverters()
@@ -89,13 +89,14 @@ void Add(JsonConverter converter) =>
8989
converters.Add(converter.Type!, converter);
9090
}
9191

92+
[RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
93+
[RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
9294
private static JsonConverter GetBuiltInConverter(Type typeToConvert)
9395
{
94-
Debug.Assert(s_defaultSimpleConverters != null);
95-
Debug.Assert(s_defaultFactoryConverters != null);
96+
s_defaultSimpleConverters ??= GetDefaultSimpleConverters();
97+
s_defaultFactoryConverters ??= GetDefaultFactoryConverters();
9698

97-
JsonConverter? converter;
98-
if (s_defaultSimpleConverters.TryGetValue(typeToConvert, out converter))
99+
if (s_defaultSimpleConverters.TryGetValue(typeToConvert, out JsonConverter? converter))
99100
{
100101
return converter;
101102
}
@@ -142,8 +143,6 @@ internal static bool TryGetDefaultSimpleConverter(Type typeToConvert, [NotNullWh
142143
[RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
143144
internal static JsonConverter GetConverterForType(Type typeToConvert, JsonSerializerOptions options, bool resolveJsonConverterAttribute = true)
144145
{
145-
RootDefaultInstance(); // Ensure default converters are rooted.
146-
147146
// Priority 1: Attempt to get custom converter from the Converters list.
148147
JsonConverter? converter = options.GetConverterFromList(typeToConvert);
149148

src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/DefaultJsonTypeInfoResolver.cs

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,6 @@ public DefaultJsonTypeInfoResolver() : this(mutable: true)
3131
private DefaultJsonTypeInfoResolver(bool mutable)
3232
{
3333
_mutable = mutable;
34-
35-
s_defaultFactoryConverters ??= GetDefaultFactoryConverters();
36-
s_defaultSimpleConverters ??= GetDefaultSimpleConverters();
3734
}
3835

3936
/// <summary>
@@ -127,21 +124,22 @@ bool IBuiltInJsonTypeInfoResolver.IsCompatibleWithOptions(JsonSerializerOptions
127124
// provided that no user extensions have been made on the class.
128125
=> _modifiers is null or { Count: 0 } && GetType() == typeof(DefaultJsonTypeInfoResolver);
129126

130-
internal static bool IsDefaultInstanceRooted => s_defaultInstance is not null;
131-
private static DefaultJsonTypeInfoResolver? s_defaultInstance;
132-
133-
[RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
134-
[RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
135-
internal static DefaultJsonTypeInfoResolver RootDefaultInstance()
127+
internal static DefaultJsonTypeInfoResolver DefaultInstance
136128
{
137-
if (s_defaultInstance is DefaultJsonTypeInfoResolver result)
129+
[RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
130+
[RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
131+
get
138132
{
139-
return result;
140-
}
133+
if (s_defaultInstance is DefaultJsonTypeInfoResolver result)
134+
{
135+
return result;
136+
}
141137

142-
var newInstance = new DefaultJsonTypeInfoResolver(mutable: false);
143-
DefaultJsonTypeInfoResolver? originalInstance = Interlocked.CompareExchange(ref s_defaultInstance, newInstance, comparand: null);
144-
return originalInstance ?? newInstance;
138+
var newInstance = new DefaultJsonTypeInfoResolver(mutable: false);
139+
return Interlocked.CompareExchange(ref s_defaultInstance, newInstance, comparand: null) ?? newInstance;
140+
}
145141
}
142+
143+
private static DefaultJsonTypeInfoResolver? s_defaultInstance;
146144
}
147145
}

src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CacheTests.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,6 @@ static Func<JsonSerializerOptions, int> CreateCacheCountAccessor()
257257

258258
[ActiveIssue("https://github.com/dotnet/runtime/issues/66232", TargetFrameworkMonikers.NetFramework)]
259259
[ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
260-
[MemberData(nameof(GetJsonSerializerOptions))]
261260
public static void JsonSerializerOptions_ReuseConverterCaches()
262261
{
263262
// This test uses reflection to:

src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/OptionsTests.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1039,11 +1039,27 @@ public static void JsonSerializerOptions_Default_IsReadOnly()
10391039
[Fact]
10401040
public static void JsonSerializerOptions_Web_MatchesConstructorWithJsonSerializerDefaults()
10411041
{
1042-
var options = new JsonSerializerOptions(JsonSerializerDefaults.Web);
1042+
var options = new JsonSerializerOptions(JsonSerializerDefaults.Web)
1043+
{
1044+
TypeInfoResolver = JsonSerializerOptions.Default.TypeInfoResolver
1045+
};
1046+
10431047
JsonSerializerOptions optionsSingleton = JsonSerializerOptions.Web;
1048+
1049+
Assert.Equal(JsonNamingPolicy.CamelCase, options.PropertyNamingPolicy);
1050+
Assert.True(options.PropertyNameCaseInsensitive);
1051+
Assert.Equal(JsonNumberHandling.AllowReadingFromString, options.NumberHandling);
1052+
10441053
JsonTestHelper.AssertOptionsEqual(options, optionsSingleton);
10451054
}
10461055

1056+
[Fact]
1057+
public static void JsonSerializerOptions_Web_SerializesWithExpectedSettings()
1058+
{
1059+
string json = JsonSerializer.Serialize(new { PropertyName = 42 }, JsonSerializerOptions.Web);
1060+
Assert.Equal("""{"propertyName":42}""", json);
1061+
}
1062+
10471063
[Fact]
10481064
public static void JsonSerializerOptions_Web_ReturnsSameInstance()
10491065
{

0 commit comments

Comments
 (0)