Skip to content

Commit

Permalink
Expose the feature switch as a property on JsonSerializer -- rename f…
Browse files Browse the repository at this point in the history
…eature switch to match namespace.
  • Loading branch information
eiriktsarpalis committed Apr 3, 2023
1 parent 145207c commit 1d9f86b
Show file tree
Hide file tree
Showing 10 changed files with 50 additions and 23 deletions.
1 change: 1 addition & 0 deletions src/libraries/System.Text.Json/ref/System.Text.Json.cs
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ public static partial class JsonSerializer
[System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
public static TValue? Deserialize<TValue>(ref System.Text.Json.Utf8JsonReader reader, System.Text.Json.JsonSerializerOptions? options = null) { throw null; }
public static TValue? Deserialize<TValue>(ref System.Text.Json.Utf8JsonReader reader, System.Text.Json.Serialization.Metadata.JsonTypeInfo<TValue> jsonTypeInfo) { throw null; }
public static bool IsReflectionEnabledByDefault { get { throw null; } }
public static void Serialize(System.IO.Stream utf8Json, object? value, System.Text.Json.Serialization.Metadata.JsonTypeInfo jsonTypeInfo) { }
[System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed and might need runtime code generation. Use System.Text.Json source generation for native AOT applications.")]
[System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<linker>
<assembly fullname="System.Text.Json">
<type fullname="System.Text.Json.AppContextSwitchHelper">
<method signature="System.Boolean get_UseReflectionDefault()" body="stub" value="false"
feature="System.Text.Json.Serialization.UseReflectionDefault" featurevalue="false"/>
<type fullname="System.Text.Json.JsonSerializer">
<method signature="System.Boolean get_IsReflectionEnabledByDefault()" body="stub" value="false"
feature="System.Text.Json.JsonSerializer.IsReflectionEnabledByDefault" featurevalue="false"/>
</type>
</assembly>
</linker>
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,6 @@ namespace System.Text.Json
{
internal static class AppContextSwitchHelper
{
public static bool UseReflectionDefault { get; } =
AppContext.TryGetSwitch(
switchName: "System.Text.Json.Serialization.UseReflectionDefault",
isEnabled: out bool value)
? value : true;

public static bool IsSourceGenReflectionFallbackEnabled { get; } =
AppContext.TryGetSwitch(
switchName: "System.Text.Json.Serialization.EnableSourceGenReflectionFallback",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,21 @@ public static partial class JsonSerializer
internal const string SerializationUnreferencedCodeMessage = "JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.";
internal const string SerializationRequiresDynamicCodeMessage = "JSON serialization and deserialization might require types that cannot be statically analyzed and might need runtime code generation. Use System.Text.Json source generation for native AOT applications.";

/// <summary>
/// Indicates whether unconfigured <see cref="JsonSerializerOptions"/> instances
/// should be set to use the reflection-based <see cref="DefaultJsonTypeInfoResolver"/>.
/// </summary>
/// <remarks>
/// The value of the property is backed by the "System.Text.Json.JsonSerializer.IsReflectionEnabledByDefault"
/// feature switch and defaults to <see langword="true"/> if unset. For trimmed applications, disabling the feature switch
/// at link time will result in the property being substituted with a constant <see langword="false"/> value.
/// </remarks>
public static bool IsReflectionEnabledByDefault { get; } =
AppContext.TryGetSwitch(
switchName: "System.Text.Json.JsonSerializer.IsReflectionEnabledByDefault",
isEnabled: out bool value)
? value : true;

[RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)]
[RequiresDynamicCode(SerializationRequiresDynamicCodeMessage)]
private static JsonTypeInfo GetTypeInfo(JsonSerializerOptions? options, Type inputType, bool fallBackToNearestAncestorType = false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public JsonConverter GetConverter(Type typeToConvert)
ThrowHelper.ThrowArgumentNullException(nameof(typeToConvert));
}

if (AppContextSwitchHelper.UseReflectionDefault && _typeInfoResolver is null)
if (JsonSerializer.IsReflectionEnabledByDefault && _typeInfoResolver is null)
{
// Backward compatibility -- root & query the default reflection converters
// but do not populate the TypeInfoResolver setting.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -680,7 +680,7 @@ public void MakeReadOnly()
[RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
internal void ConfigureForJsonSerializer()
{
if (AppContextSwitchHelper.UseReflectionDefault)
if (JsonSerializer.IsReflectionEnabledByDefault)
{
// Even if a resolver has already been specified, we need to root
// the default resolver to gain access to the default converters.
Expand Down Expand Up @@ -834,7 +834,7 @@ private static JsonSerializerOptions GetOrCreateDefaultOptionsInstance()
// we need to specify a resolver instance for the case where
// reflection is disabled by default: use one that returns null for all types.

TypeInfoResolver = AppContextSwitchHelper.UseReflectionDefault
TypeInfoResolver = JsonSerializer.IsReflectionEnabledByDefault
? DefaultJsonTypeInfoResolver.RootDefaultInstance()
: new JsonTypeInfoResolverChain(),

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -481,20 +481,28 @@ public static void Options_JsonSerializerContext_DoesNotFallbackToReflection()
Assert.Throws<NotSupportedException>(() => JsonSerializer.Serialize(unsupportedValue, options));
}

[Fact]
public static void JsonSerializer_IsReflectionEnabledByDefault_DefaultsToTrue()
{
Assert.True(JsonSerializer.IsReflectionEnabledByDefault);
}

[SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
[ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
public static void Options_DisablingUseReflectionDefaultSwitch_DefaultOptionsDoesNotSupportReflection()
public static void Options_DisablingIsReflectionEnabledByDefaultSwitch_DefaultOptionsDoesNotSupportReflection()
{
var options = new RemoteInvokeOptions
{
RuntimeConfigurationOptions =
{
["System.Text.Json.Serialization.UseReflectionDefault"] = false
["System.Text.Json.JsonSerializer.IsReflectionEnabledByDefault"] = false
}
};

RemoteExecutor.Invoke(static () =>
{
Assert.False(JsonSerializer.IsReflectionEnabledByDefault);
var options = JsonSerializerOptions.Default;
Assert.True(options.IsReadOnly);
Expand All @@ -519,18 +527,20 @@ public static void Options_DisablingUseReflectionDefaultSwitch_DefaultOptionsDoe

[SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
[ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
public static void Options_DisablingUseReflectionDefaultSwitch_NewOptionsDoesNotSupportReflection()
public static void Options_DisablingIsReflectionEnabledByDefaultSwitch_NewOptionsDoesNotSupportReflection()
{
var options = new RemoteInvokeOptions
{
RuntimeConfigurationOptions =
{
["System.Text.Json.Serialization.UseReflectionDefault"] = false
["System.Text.Json.JsonSerializer.IsReflectionEnabledByDefault"] = false
}
};

RemoteExecutor.Invoke(static () =>
{
Assert.False(JsonSerializer.IsReflectionEnabledByDefault);
var options = new JsonSerializerOptions();
Assert.False(options.IsReadOnly);
Expand Down Expand Up @@ -561,18 +571,20 @@ public static void Options_DisablingUseReflectionDefaultSwitch_NewOptionsDoesNot

[SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
[ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
public static void Options_DisablingUseReflectionDefaultSwitch_CanUseSourceGen()
public static void Options_DisablingIsReflectionEnabledByDefaultSwitch_CanUseSourceGen()
{
var options = new RemoteInvokeOptions
{
RuntimeConfigurationOptions =
{
["System.Text.Json.Serialization.UseReflectionDefault"] = false
["System.Text.Json.JsonSerializer.IsReflectionEnabledByDefault"] = false
}
};

RemoteExecutor.Invoke(static () =>
{
Assert.False(JsonSerializer.IsReflectionEnabledByDefault);
var options = new JsonSerializerOptions();
options.TypeInfoResolverChain.Add(JsonContext.Default);
Expand Down Expand Up @@ -654,19 +666,21 @@ public static void Options_JsonSerializerContext_Net6CompatibilitySwitch_FallsBa

[SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
[ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
public static void Options_JsonSerializerContext_Net6CompatibilitySwitch_IsOverriddenByDisablingUseReflectionDefault()
public static void Options_JsonSerializerContext_Net6CompatibilitySwitch_IsOverriddenByDisablingIsReflectionEnabledByDefault()
{
var options = new RemoteInvokeOptions
{
RuntimeConfigurationOptions =
{
["System.Text.Json.Serialization.UseReflectionDefault"] = false,
["System.Text.Json.JsonSerializer.IsReflectionEnabledByDefault"] = false,
["System.Text.Json.Serialization.EnableSourceGenReflectionFallback"] = true
}
};

RemoteExecutor.Invoke(static () =>
{
Assert.False(JsonSerializer.IsReflectionEnabledByDefault);
JsonContext context = JsonContext.Default;
var unsupportedValue = new MyClass();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,9 @@
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework'">
<Compile Include="$(CommonPath)System\Buffers\ArrayBufferWriter.cs" Link="CommonTest\System\Buffers\ArrayBufferWriter.cs" />
</ItemGroup>
<ItemGroup>
<None Include="TrimmingTests\IsReflectionEnabledByDefaultFalse.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(LibrariesProjectRoot)System.IO.Pipelines\src\System.IO.Pipelines.csproj" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
public static class Program
{
// Validates that expected the components are trimmed when
// the UseReflectionDefault feature switch is turned on.
// the IsReflectionEnabledByDefault feature switch is turned on.
public static int Main()
{
MyPoco valueToSerialize = new MyPoco { Value = 42 };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@
<TestConsoleAppSourceFiles Include="EnumConverterTest.cs" />
<TestConsoleAppSourceFiles Include="JsonConverterAttributeTest.cs" />
<TestConsoleAppSourceFiles Include="StackOrQueueNotRootedTest.cs" />
<TestConsoleAppSourceFiles Include="UseReflectionDefaultFalse.cs">
<DisabledFeatureSwitches>System.Text.Json.Serialization.UseReflectionDefault</DisabledFeatureSwitches>
<TestConsoleAppSourceFiles Include="IsReflectionEnabledByDefaultFalse.cs">
<DisabledFeatureSwitches>System.Text.Json.JsonSerializer.IsReflectionEnabledByDefault</DisabledFeatureSwitches>
</TestConsoleAppSourceFiles>
</ItemGroup>

Expand Down

0 comments on commit 1d9f86b

Please sign in to comment.