diff --git a/src/libraries/System.Text.Json/src/System/ReflectionExtensions.cs b/src/libraries/System.Text.Json/src/System/ReflectionExtensions.cs
index e15e8993889e43..a89745d8e1301d 100644
--- a/src/libraries/System.Text.Json/src/System/ReflectionExtensions.cs
+++ b/src/libraries/System.Text.Json/src/System/ReflectionExtensions.cs
@@ -91,15 +91,19 @@ private static bool HasCustomAttributeWithName(this ICustomAttributeProvider mem
///
/// Polyfill for BindingFlags.DoNotWrapExceptions
///
- public static object? InvokeNoWrapExceptions(this MethodInfo methodInfo, object? obj, object?[] parameters)
+ public static object? CreateInstanceNoWrapExceptions(
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicConstructors)] this Type type,
+ Type[] parameterTypes,
+ object?[] parameters)
{
+ ConstructorInfo ctorInfo = type.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, parameterTypes, null)!;
#if NETCOREAPP
- return methodInfo.Invoke(obj, BindingFlags.DoNotWrapExceptions, null, parameters, null);
+ return ctorInfo.Invoke(BindingFlags.DoNotWrapExceptions, null, parameters, null);
#else
object? result = null;
try
{
- result = methodInfo.Invoke(obj, parameters);
+ result = ctorInfo.Invoke(parameters);
}
catch (TargetInvocationException ex)
{
diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverter.cs
index 652637873a2d57..bfdb8479a4e3f8 100644
--- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverter.cs
+++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverter.cs
@@ -69,6 +69,22 @@ internal virtual void ReadElementAndSetProperty(
throw new InvalidOperationException();
}
+ [RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
+ [RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
+ internal virtual JsonTypeInfo CreateReflectionJsonTypeInfo(JsonSerializerOptions options)
+ {
+ Debug.Fail("Should not be reachable.");
+
+ throw new InvalidOperationException();
+ }
+
+ internal virtual JsonTypeInfo CreateCustomJsonTypeInfo(JsonSerializerOptions options)
+ {
+ Debug.Fail("Should not be reachable.");
+
+ throw new InvalidOperationException();
+ }
+
internal abstract JsonParameterInfo CreateJsonParameterInfo();
internal abstract JsonConverter CreateCastingConverter();
diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.cs
index 522f134a952969..0a9f00a67db7dc 100644
--- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.cs
+++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization.Converters;
using System.Text.Json.Serialization.Metadata;
@@ -67,6 +68,18 @@ public override bool CanConvert(Type typeToConvert)
internal override ConverterStrategy ConverterStrategy => ConverterStrategy.Value;
+ [RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
+ [RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
+ internal sealed override JsonTypeInfo CreateReflectionJsonTypeInfo(JsonSerializerOptions options)
+ {
+ return new ReflectionJsonTypeInfo(this, options);
+ }
+
+ internal sealed override JsonTypeInfo CreateCustomJsonTypeInfo(JsonSerializerOptions options)
+ {
+ return new CustomJsonTypeInfo(this, options);
+ }
+
internal sealed override JsonParameterInfo CreateJsonParameterInfo()
{
return new JsonParameterInfo();
diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/CustomJsonTypeInfoOfT.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/CustomJsonTypeInfoOfT.cs
index a997ee01d021bc..984125dba3443e 100644
--- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/CustomJsonTypeInfoOfT.cs
+++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/CustomJsonTypeInfoOfT.cs
@@ -1,11 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System.Collections.Generic;
-using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
-using System.Reflection;
-using System.Text.Json.Serialization.Converters;
namespace System.Text.Json.Serialization.Metadata
{
diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/DefaultJsonTypeInfoResolver.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/DefaultJsonTypeInfoResolver.cs
index 4389bd9e115297..c90a5450a0458e 100644
--- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/DefaultJsonTypeInfoResolver.cs
+++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/DefaultJsonTypeInfoResolver.cs
@@ -2,8 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
+using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
-using System.Reflection;
using System.Text.Json.Reflection;
using System.Threading;
@@ -85,20 +85,26 @@ public virtual JsonTypeInfo GetTypeInfo(Type type, JsonSerializerOptions options
[RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
private static JsonTypeInfo CreateJsonTypeInfo(Type type, JsonSerializerOptions options)
{
- s_createReflectionJsonTypeInfoMethodInfo ??= typeof(DefaultJsonTypeInfoResolver).GetMethod(nameof(CreateReflectionJsonTypeInfo), BindingFlags.NonPublic | BindingFlags.Static)!;
- return (JsonTypeInfo)s_createReflectionJsonTypeInfoMethodInfo.MakeGenericMethod(type)
- .InvokeNoWrapExceptions(null, new object[] { options })!;
- }
+ JsonTypeInfo jsonTypeInfo;
+ JsonConverter converter = GetConverterForType(type, options);
- [RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
- [RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
- private static JsonTypeInfo CreateReflectionJsonTypeInfo(JsonSerializerOptions options)
- {
- JsonConverter converter = GetConverterForType(typeof(T), options);
- return new ReflectionJsonTypeInfo(converter, options);
- }
+ if (converter.TypeToConvert == type)
+ {
+ // For performance, avoid doing a reflection-based instantiation
+ // if the converter type matches that of the declared type.
+ jsonTypeInfo = converter.CreateReflectionJsonTypeInfo(options);
+ }
+ else
+ {
+ Type jsonTypeInfoType = typeof(ReflectionJsonTypeInfo<>).MakeGenericType(type);
+ jsonTypeInfo = (JsonTypeInfo)jsonTypeInfoType.CreateInstanceNoWrapExceptions(
+ parameterTypes: new Type[] { typeof(JsonConverter), typeof(JsonSerializerOptions) },
+ parameters: new object[] { converter, options })!;
+ }
- private static MethodInfo? s_createReflectionJsonTypeInfoMethodInfo;
+ Debug.Assert(jsonTypeInfo.Type == type);
+ return jsonTypeInfo;
+ }
///
/// Gets a list of user-defined callbacks that can be used to modify the initial contract.
diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfo.Cache.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfo.Cache.cs
index af6b4cf10104d5..58fe2bb1fecb0b 100644
--- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfo.Cache.cs
+++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfo.Cache.cs
@@ -4,7 +4,6 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
-using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text.Json.Reflection;
@@ -56,7 +55,7 @@ public abstract partial class JsonTypeInfo
[RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
internal JsonPropertyInfo CreatePropertyUsingReflection(Type propertyType)
{
- JsonPropertyInfo? jsonPropertyInfo;
+ JsonPropertyInfo jsonPropertyInfo;
if (Options.TryGetTypeInfoCached(propertyType, out JsonTypeInfo? jsonTypeInfo))
{
@@ -69,9 +68,10 @@ internal JsonPropertyInfo CreatePropertyUsingReflection(Type propertyType)
{
// Metadata for `propertyType` has not been registered yet.
// Use reflection to instantiate the correct JsonPropertyInfo
- s_createJsonPropertyInfo ??= typeof(JsonTypeInfo).GetMethod(nameof(CreateJsonPropertyInfo), BindingFlags.NonPublic | BindingFlags.Static)!;
- jsonPropertyInfo = (JsonPropertyInfo)s_createJsonPropertyInfo.MakeGenericMethod(propertyType)
- .InvokeNoWrapExceptions(null, new object[] { this, Options })!;
+ Type propertyInfoType = typeof(JsonPropertyInfo<>).MakeGenericType(propertyType);
+ jsonPropertyInfo = (JsonPropertyInfo)propertyInfoType.CreateInstanceNoWrapExceptions(
+ parameterTypes: new Type[] { typeof(Type), typeof(JsonTypeInfo), typeof(JsonSerializerOptions) },
+ parameters: new object[] { Type, this, Options })!;
}
Debug.Assert(jsonPropertyInfo.PropertyType == propertyType);
@@ -83,11 +83,6 @@ internal JsonPropertyInfo CreatePropertyUsingReflection(Type propertyType)
///
private protected abstract JsonPropertyInfo CreateJsonPropertyInfo(JsonTypeInfo declaringTypeInfo, JsonSerializerOptions options);
- private static JsonPropertyInfo CreateJsonPropertyInfo(JsonTypeInfo declaringTypeInfo, JsonSerializerOptions options)
- => new JsonPropertyInfo(declaringTypeInfo.Type, declaringTypeInfo, options);
-
- private static MethodInfo? s_createJsonPropertyInfo;
-
// AggressiveInlining used although a large method it is only called from one location and is on a hot path.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal JsonPropertyInfo GetProperty(
diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfo.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfo.cs
index 407cddc0f4144f..ef345aa231d6bd 100644
--- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfo.cs
+++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfo.cs
@@ -4,7 +4,6 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
-using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using System.Text.Json.Reflection;
@@ -634,8 +633,6 @@ public static JsonTypeInfo CreateJsonTypeInfo(JsonSerializerOptions option
return new CustomJsonTypeInfo(converter, options);
}
- private static MethodInfo? s_createJsonTypeInfo;
-
///
/// Creates a blank instance.
///
@@ -673,9 +670,25 @@ public static JsonTypeInfo CreateJsonTypeInfo(Type type, JsonSerializerOptions o
ThrowHelper.ThrowArgumentException_CannotSerializeInvalidType(nameof(type), type, null, null);
}
- s_createJsonTypeInfo ??= typeof(JsonTypeInfo).GetMethod(nameof(CreateJsonTypeInfo), new Type[] { typeof(JsonSerializerOptions) })!;
- return (JsonTypeInfo)s_createJsonTypeInfo.MakeGenericMethod(type)
- .InvokeNoWrapExceptions(null, new object[] { options })!;
+ JsonTypeInfo jsonTypeInfo;
+ JsonConverter converter = DefaultJsonTypeInfoResolver.GetConverterForType(type, options, resolveJsonConverterAttribute: false);
+
+ if (converter.TypeToConvert == type)
+ {
+ // For performance, avoid doing a reflection-based instantiation
+ // if the converter type matches that of the declared type.
+ jsonTypeInfo = converter.CreateCustomJsonTypeInfo(options);
+ }
+ else
+ {
+ Type jsonTypeInfoType = typeof(CustomJsonTypeInfo<>).MakeGenericType(type);
+ jsonTypeInfo = (JsonTypeInfo)jsonTypeInfoType.CreateInstanceNoWrapExceptions(
+ parameterTypes: new Type[] { typeof(JsonConverter), typeof(JsonSerializerOptions) },
+ parameters: new object[] { converter, options })!;
+ }
+
+ Debug.Assert(jsonTypeInfo.Type == type);
+ return jsonTypeInfo;
}
///
diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/ReflectionJsonTypeInfoOfT.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/ReflectionJsonTypeInfoOfT.cs
index 1e0aac32bb7e23..72fb5a48ac0ab3 100644
--- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/ReflectionJsonTypeInfoOfT.cs
+++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/ReflectionJsonTypeInfoOfT.cs
@@ -1,12 +1,10 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
-using System.Runtime.CompilerServices;
using System.Text.Json.Reflection;
namespace System.Text.Json.Serialization.Metadata