diff --git a/eng/Versions.props b/eng/Versions.props
index 9bcc7facdfbc1..3446baa3f981d 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -43,8 +43,8 @@
- 3.8.0
- 3.8.0
+ 3.9.0
+ 3.9.0
diff --git a/src/libraries/System.Text.Json/Common/JsonConstants.cs b/src/libraries/System.Text.Json/Common/JsonConstants.cs
new file mode 100644
index 0000000000000..a97b11cf15bf2
--- /dev/null
+++ b/src/libraries/System.Text.Json/Common/JsonConstants.cs
@@ -0,0 +1,11 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace System.Text.Json
+{
+ internal static partial class JsonConstants
+ {
+ // The maximum number of parameters a constructor can have where it can be supported by the serializer.
+ public const int MaxParameterCount = 64;
+ }
+}
diff --git a/src/libraries/System.Text.Json/Common/ReflectionExtensions.cs b/src/libraries/System.Text.Json/Common/ReflectionExtensions.cs
index 623aa48fceeba..8a1a58a97a2cb 100644
--- a/src/libraries/System.Text.Json/Common/ReflectionExtensions.cs
+++ b/src/libraries/System.Text.Json/Common/ReflectionExtensions.cs
@@ -3,6 +3,7 @@
using System.Diagnostics;
using System.Reflection;
+using System.Collections.Generic;
#if !BUILDING_SOURCE_GENERATOR
using System.Diagnostics.CodeAnalysis;
#endif
@@ -229,5 +230,85 @@ public static bool IsVirtual(this PropertyInfo? propertyInfo)
Debug.Assert(propertyInfo != null);
return propertyInfo != null && (propertyInfo.GetMethod?.IsVirtual == true || propertyInfo.SetMethod?.IsVirtual == true);
}
+
+ public static bool IsKeyValuePair(this Type type, Type? keyValuePairType = null)
+ {
+ if (!type.IsGenericType)
+ {
+ return false;
+ }
+
+ // Work around not being able to use typeof(KeyValuePair<,>) directly during compile-time src gen type analysis.
+ keyValuePairType ??= typeof(KeyValuePair<,>);
+
+ Type generic = type.GetGenericTypeDefinition();
+ return generic == keyValuePairType;
+ }
+
+ public static bool TryGetDeserializationConstructor(
+#if !BUILDING_SOURCE_GENERATOR
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)]
+#endif
+ this Type type,
+ bool useDefaultCtorInAnnotatedStructs,
+ out ConstructorInfo? deserializationCtor)
+ {
+ ConstructorInfo? ctorWithAttribute = null;
+ ConstructorInfo? publicParameterlessCtor = null;
+ ConstructorInfo? lonePublicCtor = null;
+
+ ConstructorInfo[] constructors = type.GetConstructors(BindingFlags.Public | BindingFlags.Instance);
+
+ if (constructors.Length == 1)
+ {
+ lonePublicCtor = constructors[0];
+ }
+
+ foreach (ConstructorInfo constructor in constructors)
+ {
+ if (HasJsonConstructorAttribute(constructor))
+ {
+ if (ctorWithAttribute != null)
+ {
+ deserializationCtor = null;
+ return false;
+ }
+
+ ctorWithAttribute = constructor;
+ }
+ else if (constructor.GetParameters().Length == 0)
+ {
+ publicParameterlessCtor = constructor;
+ }
+ }
+
+ // For correctness, throw if multiple ctors have [JsonConstructor], even if one or more are non-public.
+ ConstructorInfo? dummyCtorWithAttribute = ctorWithAttribute;
+
+ constructors = type.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance);
+ foreach (ConstructorInfo constructor in constructors)
+ {
+ if (HasJsonConstructorAttribute(constructor))
+ {
+ if (dummyCtorWithAttribute != null)
+ {
+ deserializationCtor = null;
+ return false;
+ }
+
+ dummyCtorWithAttribute = constructor;
+ }
+ }
+
+ // Structs will use default constructor if attribute isn't used.
+ if (useDefaultCtorInAnnotatedStructs && type.IsValueType && ctorWithAttribute == null)
+ {
+ deserializationCtor = null;
+ return true;
+ }
+
+ deserializationCtor = ctorWithAttribute ?? publicParameterlessCtor ?? lonePublicCtor;
+ return true;
+ }
}
}
diff --git a/src/libraries/System.Text.Json/gen/ClassType.cs b/src/libraries/System.Text.Json/gen/ClassType.cs
index fa6aab3d2573b..d0df94330ec8e 100644
--- a/src/libraries/System.Text.Json/gen/ClassType.cs
+++ b/src/libraries/System.Text.Json/gen/ClassType.cs
@@ -16,6 +16,6 @@ internal enum ClassType
Enumerable = 4,
Dictionary = 5,
Nullable = 6,
- Enum = 7,
+ Enum = 7
}
}
diff --git a/src/libraries/System.Text.Json/gen/ContextGenerationSpec.cs b/src/libraries/System.Text.Json/gen/ContextGenerationSpec.cs
index 1339e4b9d167b..545d5628297b8 100644
--- a/src/libraries/System.Text.Json/gen/ContextGenerationSpec.cs
+++ b/src/libraries/System.Text.Json/gen/ContextGenerationSpec.cs
@@ -21,7 +21,7 @@ internal sealed class ContextGenerationSpec
public List RootSerializableTypes { get; } = new();
- public HashSet? NullableUnderlyingTypes { get; } = new();
+ public HashSet? ImplicitlyRegisteredTypes { get; } = new();
public List ContextClassDeclarationList { get; init; }
diff --git a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs
index fe8447e1309a8..118a113910a7c 100644
--- a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs
+++ b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs
@@ -6,6 +6,7 @@
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Text.Json;
+using System.Text.Json.Reflection;
using System.Text.Json.Serialization;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
@@ -20,6 +21,7 @@ private sealed partial class Emitter
private const string RuntimeCustomConverterFetchingMethodName = "GetRuntimeProvidedCustomConverter";
private const string OptionsInstanceVariableName = "Options";
private const string PropInitMethodNameSuffix = "PropInit";
+ private const string CtorParamInitMethodNameSuffix = "CtorParamInit";
private const string SerializeMethodNameSuffix = "Serialize";
private const string CreateValueInfoMethodName = "CreateValueInfo";
private const string DefaultOptionsStaticVarName = "s_defaultOptions";
@@ -55,6 +57,8 @@ private sealed partial class Emitter
private const string JsonNumberHandlingTypeRef = "global::System.Text.Json.Serialization.JsonNumberHandling";
private const string JsonSerializerContextTypeRef = "global::System.Text.Json.Serialization.JsonSerializerContext";
private const string JsonMetadataServicesTypeRef = "global::System.Text.Json.Serialization.Metadata.JsonMetadataServices";
+ private const string JsonObjectInfoValuesTypeRef = "global::System.Text.Json.Serialization.Metadata.JsonObjectInfoValues";
+ private const string JsonParameterInfoValuesTypeRef = "global::System.Text.Json.Serialization.Metadata.JsonParameterInfoValues";
private const string JsonPropertyInfoTypeRef = "global::System.Text.Json.Serialization.Metadata.JsonPropertyInfo";
private const string JsonTypeInfoTypeRef = "global::System.Text.Json.Serialization.Metadata.JsonTypeInfo";
@@ -213,11 +217,16 @@ private void GenerateTypeInfo(TypeGenerationSpec typeGenerationSpec)
{
source = GenerateForObject(typeGenerationSpec);
- if (typeGenerationSpec.PropertyGenSpecList != null)
+ foreach (PropertyGenerationSpec spec in typeGenerationSpec.PropertyGenSpecList)
{
- foreach (PropertyGenerationSpec metadata in typeGenerationSpec.PropertyGenSpecList)
+ GenerateTypeInfo(spec.TypeGenerationSpec);
+ }
+
+ if (typeGenerationSpec.ConstructionStrategy == ObjectConstructionStrategy.ParameterizedConstructor)
+ {
+ foreach (ParameterGenerationSpec spec in typeGenerationSpec.CtorParamGenSpecArray!)
{
- GenerateTypeInfo(metadata.TypeGenerationSpec);
+ GenerateTypeInfo(spec.TypeGenerationSpec);
}
}
}
@@ -541,74 +550,77 @@ private string GenerateFastPathFuncForDictionary(TypeGenerationSpec typeGenerati
private string GenerateForObject(TypeGenerationSpec typeMetadata)
{
string typeFriendlyName = typeMetadata.TypeInfoPropertyName;
+ ObjectConstructionStrategy constructionStrategy = typeMetadata.ConstructionStrategy;
- string createObjectFuncTypeArg = typeMetadata.ConstructionStrategy == ObjectConstructionStrategy.ParameterlessConstructor
- ? $"createObjectFunc: static () => new {typeMetadata.TypeRef}()"
- : "createObjectFunc: null";
+ string creatorInvocation = constructionStrategy == ObjectConstructionStrategy.ParameterlessConstructor
+ ? $"static () => new {typeMetadata.TypeRef}()"
+ : "null";
- string propInitMethodName = $"{typeFriendlyName}{PropInitMethodNameSuffix}";
- string? propMetadataInitFuncSource = null;
- string propMetadataInitFuncNamedArg;
+ string parameterizedCreatorInvocation = constructionStrategy == ObjectConstructionStrategy.ParameterizedConstructor
+ ? GetParameterizedCtorInvocationFunc(typeMetadata)
+ : "null";
- string serializeMethodName = $"{typeFriendlyName}{SerializeMethodNameSuffix}";
+ string? propMetadataInitFuncSource = null;
+ string? ctorParamMetadataInitFuncSource = null;
string? serializeFuncSource = null;
- string serializeFuncNamedArg;
+
+ string propInitMethodName = "null";
+ string ctorParamMetadataInitMethodName = "null";
+ string serializeMethodName = "null";
if (typeMetadata.GenerateMetadata)
{
- propMetadataInitFuncSource = GeneratePropMetadataInitFunc(typeMetadata.IsValueType, propInitMethodName, typeMetadata.PropertyGenSpecList!);
- propMetadataInitFuncNamedArg = $@"propInitFunc: {propInitMethodName}";
- }
- else
- {
- propMetadataInitFuncNamedArg = @"propInitFunc: null";
+ propMetadataInitFuncSource = GeneratePropMetadataInitFunc(typeMetadata);
+ propInitMethodName = $"{typeFriendlyName}{PropInitMethodNameSuffix}";
+
+ if (constructionStrategy == ObjectConstructionStrategy.ParameterizedConstructor)
+ {
+ ctorParamMetadataInitFuncSource = GenerateCtorParamMetadataInitFunc(typeMetadata);
+ ctorParamMetadataInitMethodName = $"{typeFriendlyName}{CtorParamInitMethodNameSuffix}";
+ }
}
if (typeMetadata.GenerateSerializationLogic)
{
- serializeFuncSource = GenerateFastPathFuncForObject(typeMetadata, serializeMethodName);
- serializeFuncNamedArg = $@"serializeFunc: {serializeMethodName}";
- }
- else
- {
- serializeFuncNamedArg = @"serializeFunc: null";
+ serializeFuncSource = GenerateFastPathFuncForObject(typeMetadata);
+ serializeMethodName = $"{typeFriendlyName}{SerializeMethodNameSuffix}";
}
- string objectInfoInitSource = $@"_{typeFriendlyName} = {JsonMetadataServicesTypeRef}.CreateObjectInfo<{typeMetadata.TypeRef}>(
- {OptionsInstanceVariableName},
- {createObjectFuncTypeArg},
- {propMetadataInitFuncNamedArg},
- {GetNumberHandlingAsStr(typeMetadata.NumberHandling)},
- {serializeFuncNamedArg});";
+ const string ObjectInfoVarName = "objectInfo";
+ string genericArg = typeMetadata.TypeRef;
- string additionalSource;
- if (propMetadataInitFuncSource == null || serializeFuncSource == null)
- {
- additionalSource = propMetadataInitFuncSource ?? serializeFuncSource;
- }
- else
- {
- additionalSource = @$"{propMetadataInitFuncSource}{serializeFuncSource}";
- }
+ string objectInfoInitSource = $@"{JsonObjectInfoValuesTypeRef}<{genericArg}> {ObjectInfoVarName} = new {JsonObjectInfoValuesTypeRef}<{genericArg}>()
+ {{
+ ObjectCreator = {creatorInvocation},
+ ObjectWithParameterizedConstructorCreator = {parameterizedCreatorInvocation},
+ PropertyMetadataInitializer = {propInitMethodName},
+ ConstructorParameterMetadataInitializer = {ctorParamMetadataInitMethodName},
+ NumberHandling = {GetNumberHandlingAsStr(typeMetadata.NumberHandling)},
+ SerializeHandler = {serializeMethodName}
+ }};
+
+ _{typeFriendlyName} = {JsonMetadataServicesTypeRef}.CreateObjectInfo<{typeMetadata.TypeRef}>({OptionsInstanceVariableName}, {ObjectInfoVarName});";
+
+ string additionalSource = @$"{propMetadataInitFuncSource}{serializeFuncSource}{ctorParamMetadataInitFuncSource}";
return GenerateForType(typeMetadata, objectInfoInitSource, additionalSource);
}
- private string GeneratePropMetadataInitFunc(
- bool declaringTypeIsValueType,
- string propInitMethodName,
- List properties)
+ private string GeneratePropMetadataInitFunc(TypeGenerationSpec typeGenerationSpec)
{
const string PropVarName = "properties";
const string JsonContextVarName = "jsonContext";
+ List properties = typeGenerationSpec.PropertyGenSpecList!;
+
int propCount = properties.Count;
- string propertyArrayInstantiationValue = properties == null
+ string propertyArrayInstantiationValue = propCount == 0
? $"{ArrayTypeRef}.Empty<{JsonPropertyInfoTypeRef}>()"
: $"new {JsonPropertyInfoTypeRef}[{propCount}]";
string contextTypeRef = _currentContext.ContextTypeRef;
+ string propInitMethodName = $"{typeGenerationSpec.TypeInfoPropertyName}{PropInitMethodNameSuffix}";
StringBuilder sb = new();
@@ -649,7 +661,7 @@ private string GeneratePropMetadataInitFunc(
string setterNamedArg;
if (memberMetadata.CanUseSetter)
{
- string propMutation = declaringTypeIsValueType
+ string propMutation = typeGenerationSpec.IsValueType
? @$"{UnsafeTypeRef}.Unbox<{declaringTypeCompilableName}>(obj).{clrPropertyName} = value"
: $@"(({declaringTypeCompilableName})obj).{clrPropertyName} = value";
@@ -697,10 +709,52 @@ private string GeneratePropMetadataInitFunc(
return sb.ToString();
}
- private string GenerateFastPathFuncForObject(TypeGenerationSpec typeGenSpec, string serializeMethodName)
+ private string GenerateCtorParamMetadataInitFunc(TypeGenerationSpec typeGenerationSpec)
+ {
+ const string parametersVarName = "parameters";
+ const string infoVarName = "info";
+
+ ParameterGenerationSpec[] parameters = typeGenerationSpec.CtorParamGenSpecArray;
+ int paramCount = parameters.Length;
+ Debug.Assert(paramCount > 0);
+
+ StringBuilder sb = new($@"
+
+private static {JsonParameterInfoValuesTypeRef}[] {typeGenerationSpec.TypeInfoPropertyName}{CtorParamInitMethodNameSuffix}()
+{{
+ {JsonParameterInfoValuesTypeRef}[] {parametersVarName} = new {JsonParameterInfoValuesTypeRef}[{paramCount}];
+ {JsonParameterInfoValuesTypeRef} info;
+");
+
+ for (int i = 0; i < paramCount; i++)
+ {
+ ParameterInfo reflectionInfo = parameters[i].ParameterInfo;
+
+ sb.Append(@$"
+ {infoVarName} = new()
+ {{
+ Name = ""{reflectionInfo.Name!}"",
+ ParameterType = typeof({reflectionInfo.ParameterType.GetCompilableName()}),
+ Position = {reflectionInfo.Position},
+ HasDefaultValue = {ToCSharpKeyword(reflectionInfo.HasDefaultValue)},
+ DefaultValue = {GetParamDefaultValueAsString(reflectionInfo.DefaultValue)}
+ }};
+ {parametersVarName}[{i}] = {infoVarName};
+");
+ }
+
+ sb.Append(@$"
+ return {parametersVarName};
+}}");
+
+ return sb.ToString();
+ }
+
+ private string GenerateFastPathFuncForObject(TypeGenerationSpec typeGenSpec)
{
JsonSourceGenerationOptionsAttribute options = _currentContext.GenerationOptions;
string typeRef = typeGenSpec.TypeRef;
+ string serializeMethodName = $"{typeGenSpec.TypeInfoPropertyName}{SerializeMethodNameSuffix}";
if (!typeGenSpec.TryFilterSerializableProps(
options,
@@ -842,6 +896,35 @@ private static bool ShouldIncludePropertyForFastPath(PropertyGenerationSpec prop
return true;
}
+ private static string GetParameterizedCtorInvocationFunc(TypeGenerationSpec typeGenerationSpec)
+ {
+ ParameterGenerationSpec[] parameters = typeGenerationSpec.CtorParamGenSpecArray;
+ int paramCount = parameters.Length;
+ Debug.Assert(paramCount != 0);
+
+ if (paramCount > JsonConstants.MaxParameterCount)
+ {
+ return "null";
+ }
+
+ const string ArgsVarName = "args";
+ int lastIndex = paramCount - 1;
+
+ StringBuilder sb = new($"static ({ArgsVarName}) => new {typeGenerationSpec.TypeRef}(");
+
+ for (int i = 0; i < lastIndex; i++)
+ {
+ sb.Append($"{GetParamUnboxing(parameters[i], i)}, ");
+ }
+
+ sb.Append($"{GetParamUnboxing(parameters[lastIndex], lastIndex)})");
+
+ return sb.ToString();
+
+ static string GetParamUnboxing(ParameterGenerationSpec spec, int index)
+ => $"({spec.ParameterInfo.ParameterType.GetCompilableName()}){ArgsVarName}[{index}]";
+ }
+
private string? GetWriterMethod(Type type)
{
string? method;
@@ -1066,7 +1149,7 @@ private string GetGetTypeInfoImplementation()
{{");
HashSet types = new(_currentContext.RootSerializableTypes);
- types.UnionWith(_currentContext.NullableUnderlyingTypes);
+ types.UnionWith(_currentContext.ImplicitlyRegisteredTypes);
// TODO (https://github.com/dotnet/runtime/issues/52218): Make this Dictionary-lookup-based if root-serializable type count > 64.
foreach (TypeGenerationSpec metadata in types)
@@ -1122,5 +1205,18 @@ private static string GetNumberHandlingAsStr(JsonNumberHandling? numberHandling)
}
private static string ToCSharpKeyword(bool value) => value.ToString().ToLowerInvariant();
+
+ private static string GetParamDefaultValueAsString(object? value)
+ {
+ switch (value)
+ {
+ case null:
+ return "null";
+ case bool boolVal:
+ return ToCSharpKeyword(boolVal);
+ default:
+ return value!.ToString();
+ }
+ }
}
}
diff --git a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs
index 184a1774c29cd..b763eb5a1390c 100644
--- a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs
+++ b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs
@@ -29,7 +29,6 @@ private sealed class Parser
private const string JsonIncludeAttributeFullName = "System.Text.Json.Serialization.JsonIncludeAttribute";
private const string JsonNumberHandlingAttributeFullName = "System.Text.Json.Serialization.JsonNumberHandlingAttribute";
private const string JsonPropertyNameAttributeFullName = "System.Text.Json.Serialization.JsonPropertyNameAttribute";
-
private const string JsonPropertyOrderAttributeFullName = "System.Text.Json.Serialization.JsonPropertyOrderAttribute";
private readonly GeneratorExecutionContext _executionContext;
@@ -53,6 +52,7 @@ private sealed class Parser
private readonly Type? _ilistType;
private readonly Type? _stackType;
private readonly Type? _queueType;
+ private readonly Type? _keyValuePair;
private readonly Type _booleanType;
private readonly Type _charType;
@@ -76,7 +76,7 @@ private sealed class Parser
///
private readonly Dictionary _typeGenerationSpecCache = new();
- private readonly HashSet _nullableTypeGenerationSpecCache = new();
+ private readonly HashSet _implicitlyRegisteredTypes = new();
private JsonKnownNamingPolicy _currentContextNamingPolicy;
@@ -88,6 +88,14 @@ private sealed class Parser
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);
+ private static DiagnosticDescriptor MultipleJsonConstructorAttribute { get; } = new DiagnosticDescriptor(
+ id: "SYSLIB1033",
+ title: new LocalizableResourceString(nameof(SR.MultipleJsonConstructorAttributeTitle), SR.ResourceManager, typeof(FxResources.System.Text.Json.SourceGeneration.SR)),
+ messageFormat: new LocalizableResourceString(nameof(SR.MultipleJsonConstructorAttributeFormat), SR.ResourceManager, typeof(FxResources.System.Text.Json.SourceGeneration.SR)),
+ category: SystemTextJsonSourceGenerationName,
+ defaultSeverity: DiagnosticSeverity.Error,
+ isEnabledByDefault: true);
+
public Parser(in GeneratorExecutionContext executionContext)
{
_executionContext = executionContext;
@@ -111,6 +119,7 @@ public Parser(in GeneratorExecutionContext executionContext)
_ilistType = ResolveType(typeof(IList).FullName!);
_stackType = ResolveType(typeof(Stack).FullName!);
_queueType = ResolveType(typeof(Queue).FullName!);
+ _keyValuePair = ResolveType(typeof(KeyValuePair<,>).FullName!);
_booleanType = ResolveType(SpecialType.System_Boolean);
_charType = ResolveType(SpecialType.System_Char);
@@ -217,14 +226,14 @@ public Parser(in GeneratorExecutionContext executionContext)
continue;
}
- contextGenSpec.NullableUnderlyingTypes.UnionWith(_nullableTypeGenerationSpecCache);
+ contextGenSpec.ImplicitlyRegisteredTypes.UnionWith(_implicitlyRegisteredTypes);
contextGenSpecList ??= new List();
contextGenSpecList.Add(contextGenSpec);
// Clear the cache of generated metadata between the processing of context classes.
_typeGenerationSpecCache.Clear();
- _nullableTypeGenerationSpecCache.Clear();
+ _implicitlyRegisteredTypes.Clear();
}
if (contextGenSpecList == null)
@@ -530,6 +539,7 @@ private TypeGenerationSpec GetOrAddTypeGenerationSpec(Type type, JsonSourceGener
TypeGenerationSpec? nullableUnderlyingTypeGenSpec = null;
List? propGenSpecList = null;
ObjectConstructionStrategy constructionStrategy = default;
+ ParameterGenerationSpec[]? paramGenSpecArray = null;
CollectionType collectionType = CollectionType.NotApplicable;
JsonNumberHandling? numberHandling = null;
bool foundDesignTimeCustomConverter = false;
@@ -541,7 +551,7 @@ private TypeGenerationSpec GetOrAddTypeGenerationSpec(Type type, JsonSourceGener
foreach (CustomAttributeData attributeData in attributeDataList)
{
Type attributeType = attributeData.AttributeType;
- if (attributeType.FullName == "System.Text.Json.Serialization.JsonNumberHandlingAttribute")
+ if (attributeType.FullName == JsonNumberHandlingAttributeFullName)
{
IList ctorArgs = attributeData.ConstructorArguments;
numberHandling = (JsonNumberHandling)ctorArgs[0].Value;
@@ -554,15 +564,6 @@ private TypeGenerationSpec GetOrAddTypeGenerationSpec(Type type, JsonSourceGener
}
}
- if (type.Name.StartsWith("StackWrapper"))
- {
- }
-
- if (type.GetConstructor(Type.EmptyTypes) != null && !type.IsAbstract && !type.IsInterface)
- {
- constructionStrategy = ObjectConstructionStrategy.ParameterlessConstructor;
- }
-
if (foundDesignTimeCustomConverter)
{
classType = converterInstatiationLogic != null
@@ -578,7 +579,7 @@ private TypeGenerationSpec GetOrAddTypeGenerationSpec(Type type, JsonSourceGener
Debug.Assert(nullableUnderlyingType != null);
classType = ClassType.Nullable;
nullableUnderlyingTypeGenSpec = GetOrAddTypeGenerationSpec(nullableUnderlyingType, generationMode);
- _nullableTypeGenerationSpecCache.Add(nullableUnderlyingTypeGenSpec);
+ _implicitlyRegisteredTypes.Add(nullableUnderlyingTypeGenSpec);
}
else if (type.IsEnum)
{
@@ -586,6 +587,11 @@ private TypeGenerationSpec GetOrAddTypeGenerationSpec(Type type, JsonSourceGener
}
else if (_ienumerableType.IsAssignableFrom(type))
{
+ if ((type.GetConstructor(Type.EmptyTypes) != null || type.IsValueType) && !type.IsAbstract && !type.IsInterface)
+ {
+ constructionStrategy = ObjectConstructionStrategy.ParameterlessConstructor;
+ }
+
Type actualTypeToConvert;
if (type.IsArray)
@@ -726,57 +732,97 @@ private TypeGenerationSpec GetOrAddTypeGenerationSpec(Type type, JsonSourceGener
}
else
{
- classType = ClassType.Object;
-
- // GetInterface() is currently not implemented, so we use GetInterfaces().
- IEnumerable interfaces = type.GetInterfaces().Select(interfaceType => interfaceType.FullName!);
- implementsIJsonOnSerialized = interfaces.FirstOrDefault(interfaceName => interfaceName == IJsonOnSerializedFullName) != null;
- implementsIJsonOnSerializing = interfaces.FirstOrDefault(interfaceName => interfaceName == IJsonOnSerializingFullName) != null;
-
- propGenSpecList = new List();
- Dictionary? ignoredMembers = null;
+ bool useDefaultCtorInAnnotatedStructs = !type.IsKeyValuePair(_keyValuePair);
- const BindingFlags bindingFlags =
- BindingFlags.Instance |
- BindingFlags.Public |
- BindingFlags.NonPublic |
- BindingFlags.DeclaredOnly;
-
- bool propertyOrderSpecified = false;
-
- for (Type? currentType = type; currentType != null; currentType = currentType.BaseType)
+ if (!type.TryGetDeserializationConstructor(useDefaultCtorInAnnotatedStructs, out ConstructorInfo? constructor))
{
- foreach (PropertyInfo propertyInfo in currentType.GetProperties(bindingFlags))
+ classType = ClassType.TypeUnsupportedBySourceGen;
+ _executionContext.ReportDiagnostic(Diagnostic.Create(MultipleJsonConstructorAttribute, Location.None, new string[] { $"{type}" }));
+ }
+ else
+ {
+ classType = ClassType.Object;
+
+ if ((constructor != null || type.IsValueType) && !type.IsAbstract)
{
- bool isVirtual = propertyInfo.IsVirtual();
+ ParameterInfo[]? parameters = constructor?.GetParameters();
+ int paramCount = parameters?.Length ?? 0;
- if (propertyInfo.GetIndexParameters().Length > 0 ||
- PropertyIsOverridenAndIgnored(propertyInfo.Name, propertyInfo.PropertyType, isVirtual, ignoredMembers))
+ if (paramCount == 0)
{
- continue;
+ constructionStrategy = ObjectConstructionStrategy.ParameterlessConstructor;
}
+ else
+ {
+ constructionStrategy = ObjectConstructionStrategy.ParameterizedConstructor;
+ paramGenSpecArray = new ParameterGenerationSpec[paramCount];
- PropertyGenerationSpec spec = GetPropertyGenerationSpec(propertyInfo, isVirtual, generationMode);
- CacheMember(spec, ref propGenSpecList, ref ignoredMembers);
- propertyOrderSpecified |= spec.Order != 0;
+ for (int i = 0; i < paramCount; i++)
+ {
+ ParameterInfo parameterInfo = parameters[i];
+ TypeGenerationSpec typeGenerationSpec = GetOrAddTypeGenerationSpec(parameterInfo.ParameterType, generationMode);
+
+ paramGenSpecArray[i] = new ParameterGenerationSpec()
+ {
+ TypeGenerationSpec = typeGenerationSpec,
+ ParameterInfo = parameterInfo
+ };
+
+ _implicitlyRegisteredTypes.Add(typeGenerationSpec);
+ }
+ }
}
- foreach (FieldInfo fieldInfo in currentType.GetFields(bindingFlags))
+ // GetInterface() is currently not implemented, so we use GetInterfaces().
+ IEnumerable interfaces = type.GetInterfaces().Select(interfaceType => interfaceType.FullName!);
+ implementsIJsonOnSerialized = interfaces.FirstOrDefault(interfaceName => interfaceName == IJsonOnSerializedFullName) != null;
+ implementsIJsonOnSerializing = interfaces.FirstOrDefault(interfaceName => interfaceName == IJsonOnSerializingFullName) != null;
+
+ propGenSpecList = new List();
+ Dictionary? ignoredMembers = null;
+
+ const BindingFlags bindingFlags =
+ BindingFlags.Instance |
+ BindingFlags.Public |
+ BindingFlags.NonPublic |
+ BindingFlags.DeclaredOnly;
+
+ bool propertyOrderSpecified = false;
+
+ for (Type? currentType = type; currentType != null; currentType = currentType.BaseType)
{
- if (PropertyIsOverridenAndIgnored(fieldInfo.Name, fieldInfo.FieldType, currentMemberIsVirtual: false, ignoredMembers))
+ foreach (PropertyInfo propertyInfo in currentType.GetProperties(bindingFlags))
{
- continue;
+ bool isVirtual = propertyInfo.IsVirtual();
+
+ if (propertyInfo.GetIndexParameters().Length > 0 ||
+ PropertyIsOverridenAndIgnored(propertyInfo.Name, propertyInfo.PropertyType, isVirtual, ignoredMembers))
+ {
+ continue;
+ }
+
+ PropertyGenerationSpec spec = GetPropertyGenerationSpec(propertyInfo, isVirtual, generationMode);
+ CacheMember(spec, ref propGenSpecList, ref ignoredMembers);
+ propertyOrderSpecified |= spec.Order != 0;
}
- PropertyGenerationSpec spec = GetPropertyGenerationSpec(fieldInfo, isVirtual: false, generationMode);
- CacheMember(spec, ref propGenSpecList, ref ignoredMembers);
- propertyOrderSpecified |= spec.Order != 0;
+ foreach (FieldInfo fieldInfo in currentType.GetFields(bindingFlags))
+ {
+ if (PropertyIsOverridenAndIgnored(fieldInfo.Name, fieldInfo.FieldType, currentMemberIsVirtual: false, ignoredMembers))
+ {
+ continue;
+ }
+
+ PropertyGenerationSpec spec = GetPropertyGenerationSpec(fieldInfo, isVirtual: false, generationMode);
+ CacheMember(spec, ref propGenSpecList, ref ignoredMembers);
+ propertyOrderSpecified |= spec.Order != 0;
+ }
}
- }
- if (propertyOrderSpecified)
- {
- propGenSpecList.Sort((p1, p2) => p1.Order.CompareTo(p2.Order));
+ if (propertyOrderSpecified)
+ {
+ propGenSpecList.Sort((p1, p2) => p1.Order.CompareTo(p2.Order));
+ }
}
}
@@ -786,6 +832,7 @@ private TypeGenerationSpec GetOrAddTypeGenerationSpec(Type type, JsonSourceGener
classType,
numberHandling,
propGenSpecList,
+ paramGenSpecArray,
collectionType,
collectionKeyTypeMetadata: collectionKeyType != null ? GetOrAddTypeGenerationSpec(collectionKeyType, generationMode) : null,
collectionValueTypeMetadata: collectionValueType != null ? GetOrAddTypeGenerationSpec(collectionValueType, generationMode) : null,
diff --git a/src/libraries/System.Text.Json/gen/ParameterGenerationSpec.cs b/src/libraries/System.Text.Json/gen/ParameterGenerationSpec.cs
new file mode 100644
index 0000000000000..00b8b840d507c
--- /dev/null
+++ b/src/libraries/System.Text.Json/gen/ParameterGenerationSpec.cs
@@ -0,0 +1,17 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Text;
+
+namespace System.Text.Json.SourceGeneration
+{
+ internal class ParameterGenerationSpec
+ {
+ public TypeGenerationSpec TypeGenerationSpec { get; init; }
+
+ public ParameterInfo ParameterInfo { get; init; }
+ }
+}
diff --git a/src/libraries/System.Text.Json/gen/Reflection/ConstructorInfoWrapper.cs b/src/libraries/System.Text.Json/gen/Reflection/ConstructorInfoWrapper.cs
index 42d167a462207..51dcef2c0af48 100644
--- a/src/libraries/System.Text.Json/gen/Reflection/ConstructorInfoWrapper.cs
+++ b/src/libraries/System.Text.Json/gen/Reflection/ConstructorInfoWrapper.cs
@@ -21,7 +21,9 @@ public ConstructorInfoWrapper(IMethodSymbol ctor, MetadataLoadContextInternal me
public override Type DeclaringType => _ctor.ContainingType.AsType(_metadataLoadContext);
- public override MethodAttributes Attributes => throw new NotImplementedException();
+ private MethodAttributes? _attributes;
+
+ public override MethodAttributes Attributes => _attributes ??= _ctor.GetMethodAttributes();
public override RuntimeMethodHandle MethodHandle => throw new NotSupportedException();
diff --git a/src/libraries/System.Text.Json/gen/Reflection/MethodInfoWrapper.cs b/src/libraries/System.Text.Json/gen/Reflection/MethodInfoWrapper.cs
index 637483847e599..4b7ef69ce483c 100644
--- a/src/libraries/System.Text.Json/gen/Reflection/MethodInfoWrapper.cs
+++ b/src/libraries/System.Text.Json/gen/Reflection/MethodInfoWrapper.cs
@@ -23,46 +23,7 @@ public MethodInfoWrapper(IMethodSymbol method, MetadataLoadContextInternal metad
private MethodAttributes? _attributes;
- public override MethodAttributes Attributes
- {
- get
- {
- if (!_attributes.HasValue)
- {
- _attributes = default(MethodAttributes);
-
- if (_method.IsAbstract)
- {
- _attributes |= MethodAttributes.Abstract;
- }
-
- if (_method.IsStatic)
- {
- _attributes |= MethodAttributes.Static;
- }
-
- if (_method.IsVirtual || _method.IsOverride)
- {
- _attributes |= MethodAttributes.Virtual;
- }
-
- switch (_method.DeclaredAccessibility)
- {
- case Accessibility.Public:
- _attributes |= MethodAttributes.Public;
- break;
- case Accessibility.Private:
- _attributes |= MethodAttributes.Private;
- break;
- case Accessibility.Internal:
- _attributes |= MethodAttributes.Assembly;
- break;
- }
- }
-
- return _attributes.Value;
- }
- }
+ public override MethodAttributes Attributes => _attributes ??= _method.GetMethodAttributes();
public override RuntimeMethodHandle MethodHandle => throw new NotSupportedException();
diff --git a/src/libraries/System.Text.Json/gen/Reflection/ParameterInfoWrapper.cs b/src/libraries/System.Text.Json/gen/Reflection/ParameterInfoWrapper.cs
index ad9091017728f..81c4cc828ae4e 100644
--- a/src/libraries/System.Text.Json/gen/Reflection/ParameterInfoWrapper.cs
+++ b/src/libraries/System.Text.Json/gen/Reflection/ParameterInfoWrapper.cs
@@ -23,6 +23,12 @@ public ParameterInfoWrapper(IParameterSymbol parameter, MetadataLoadContextInter
public override string Name => _parameter.Name;
+ public override bool HasDefaultValue => _parameter.HasExplicitDefaultValue;
+
+ public override object DefaultValue => HasDefaultValue ? _parameter.ExplicitDefaultValue : null;
+
+ public override int Position => _parameter.Ordinal;
+
public override IList GetCustomAttributesData()
{
var attributes = new List();
diff --git a/src/libraries/System.Text.Json/gen/Reflection/ReflectionExtensions.cs b/src/libraries/System.Text.Json/gen/Reflection/ReflectionExtensions.cs
index 599cae49aebd5..101f3e48fbfb7 100644
--- a/src/libraries/System.Text.Json/gen/Reflection/ReflectionExtensions.cs
+++ b/src/libraries/System.Text.Json/gen/Reflection/ReflectionExtensions.cs
@@ -1,6 +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.Linq;
using System.Reflection;
@@ -29,5 +30,20 @@ public static bool IsInitOnly(this MethodInfo method)
MethodInfoWrapper methodInfoWrapper = (MethodInfoWrapper)method;
return methodInfoWrapper.IsInitOnly;
}
+
+ private static bool HasJsonConstructorAttribute(ConstructorInfo constructorInfo)
+ {
+ IList attributeDataList = CustomAttributeData.GetCustomAttributes(constructorInfo);
+
+ foreach (CustomAttributeData attributeData in attributeDataList)
+ {
+ if (attributeData.AttributeType.FullName == "System.Text.Json.Serialization.JsonConstructorAttribute")
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
}
}
diff --git a/src/libraries/System.Text.Json/gen/Reflection/RoslynExtensions.cs b/src/libraries/System.Text.Json/gen/Reflection/RoslynExtensions.cs
index 3dd1e925e2f19..4e2479784de13 100644
--- a/src/libraries/System.Text.Json/gen/Reflection/RoslynExtensions.cs
+++ b/src/libraries/System.Text.Json/gen/Reflection/RoslynExtensions.cs
@@ -30,5 +30,40 @@ public static IEnumerable BaseTypes(this INamedTypeSymbol type
t = t.BaseType;
}
}
+
+ public static MethodAttributes GetMethodAttributes(this IMethodSymbol methodSymbol)
+ {
+ MethodAttributes attributes = default(MethodAttributes);
+
+ if (methodSymbol.IsAbstract)
+ {
+ attributes |= MethodAttributes.Abstract;
+ }
+
+ if (methodSymbol.IsStatic)
+ {
+ attributes |= MethodAttributes.Static;
+ }
+
+ if (methodSymbol.IsVirtual || methodSymbol.IsOverride)
+ {
+ attributes |= MethodAttributes.Virtual;
+ }
+
+ switch (methodSymbol.DeclaredAccessibility)
+ {
+ case Accessibility.Public:
+ attributes |= MethodAttributes.Public;
+ break;
+ case Accessibility.Private:
+ attributes |= MethodAttributes.Private;
+ break;
+ case Accessibility.Internal:
+ attributes |= MethodAttributes.Assembly;
+ break;
+ }
+
+ return attributes;
+ }
}
}
diff --git a/src/libraries/System.Text.Json/gen/Reflection/TypeWrapper.cs b/src/libraries/System.Text.Json/gen/Reflection/TypeWrapper.cs
index db2c79a949069..964f129ae7af8 100644
--- a/src/libraries/System.Text.Json/gen/Reflection/TypeWrapper.cs
+++ b/src/libraries/System.Text.Json/gen/Reflection/TypeWrapper.cs
@@ -249,7 +249,13 @@ public override ConstructorInfo[] GetConstructors(BindingFlags bindingAttr)
foreach (IMethodSymbol c in _namedTypeSymbol.Constructors)
{
- if (c.DeclaredAccessibility == Accessibility.Public)
+ if (c.IsImplicitlyDeclared && IsValueType)
+ {
+ continue;
+ }
+
+ if (((BindingFlags.Public & bindingAttr) != 0 && c.DeclaredAccessibility == Accessibility.Public) ||
+ ((BindingFlags.NonPublic & bindingAttr) != 0 && c.DeclaredAccessibility != Accessibility.Public))
{
ctors.Add(new ConstructorInfoWrapper(c, _metadataLoadContext));
}
@@ -382,6 +388,12 @@ public override PropertyInfo[] GetProperties(BindingFlags bindingAttr)
{
if (item is IPropertySymbol propertySymbol)
{
+ // Skip auto-generated properties on records.
+ if (_typeSymbol.IsRecord && propertySymbol.DeclaringSyntaxReferences.Length == 0)
+ {
+ continue;
+ }
+
// Skip if:
if (
// we want a static property and this is not static
diff --git a/src/libraries/System.Text.Json/gen/Resources/Strings.resx b/src/libraries/System.Text.Json/gen/Resources/Strings.resx
index d6d4a153ed2e3..5e60f5e377c5d 100644
--- a/src/libraries/System.Text.Json/gen/Resources/Strings.resx
+++ b/src/libraries/System.Text.Json/gen/Resources/Strings.resx
@@ -135,4 +135,10 @@
Derived 'JsonSerializerContext' types and all containing types must be partial.
+
+ Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'.
+
+
+ Type has multiple constructors annotated with JsonConstructorAttribute.
+
\ No newline at end of file
diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.cs.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.cs.xlf
index 94f13a8bc9acd..578dded931de8 100644
--- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.cs.xlf
+++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.cs.xlf
@@ -22,6 +22,16 @@
Duplicitní název typu
+
+
+ Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'.
+
+
+
+
+ Type has multiple constructors annotated with JsonConstructorAttribute.
+
+
Nevygenerovala se metadata serializace pro typ {0}.
diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.de.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.de.xlf
index e23cf13d8953e..9a154a7b3c7d2 100644
--- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.de.xlf
+++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.de.xlf
@@ -22,6 +22,16 @@
Doppelter Typname
+
+
+ Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'.
+
+
+
+
+ Type has multiple constructors annotated with JsonConstructorAttribute.
+
+
Die Serialisierungsmetadaten für den Typ "{0}" wurden nicht generiert.
diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.es.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.es.xlf
index 893e9374de74d..591795f67d7e7 100644
--- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.es.xlf
+++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.es.xlf
@@ -22,6 +22,16 @@
Nombre de tipo duplicado.
+
+
+ Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'.
+
+
+
+
+ Type has multiple constructors annotated with JsonConstructorAttribute.
+
+
No generó metadatos de serialización para el tipo '{0}".
diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.fr.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.fr.xlf
index 1a364c168966f..0a46e3e37dc7f 100644
--- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.fr.xlf
+++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.fr.xlf
@@ -22,6 +22,16 @@
Nom de type dupliqué.
+
+
+ Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'.
+
+
+
+
+ Type has multiple constructors annotated with JsonConstructorAttribute.
+
+
Les métadonnées de sérialisation pour le type « {0} » n’ont pas été générées.
diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.it.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.it.xlf
index 7a700a27d8594..663222f90862a 100644
--- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.it.xlf
+++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.it.xlf
@@ -22,6 +22,16 @@
Nome di tipo duplicato.
+
+
+ Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'.
+
+
+
+
+ Type has multiple constructors annotated with JsonConstructorAttribute.
+
+
Non sono stati generati metadati di serializzazione per il tipo '{0}'.
diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ja.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ja.xlf
index f05edfd844eaf..73b7ba0eda936 100644
--- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ja.xlf
+++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ja.xlf
@@ -22,6 +22,16 @@
重複した種類名。
+
+
+ Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'.
+
+
+
+
+ Type has multiple constructors annotated with JsonConstructorAttribute.
+
+
'{0}'型 のシリアル化メタデータを生成ませんでした。
diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ko.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ko.xlf
index 308d672c998ef..a9c2c1ee7e337 100644
--- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ko.xlf
+++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ko.xlf
@@ -22,6 +22,16 @@
중복된 형식 이름입니다.
+
+
+ Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'.
+
+
+
+
+ Type has multiple constructors annotated with JsonConstructorAttribute.
+
+
'{0}' 형식에 대한 직렬화 메타데이터가 생성되지 않았습니다.
diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pl.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pl.xlf
index 45865274732ab..97ee4a15ec077 100644
--- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pl.xlf
+++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pl.xlf
@@ -22,6 +22,16 @@
Zduplikowana nazwa typu.
+
+
+ Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'.
+
+
+
+
+ Type has multiple constructors annotated with JsonConstructorAttribute.
+
+
Nie wygenerowano metadanych serializacji dla typu „{0}”.
diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pt-BR.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pt-BR.xlf
index cb75ff91ce38c..40d8e88fa31b5 100644
--- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pt-BR.xlf
+++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pt-BR.xlf
@@ -22,6 +22,16 @@
Nome de tipo duplicado.
+
+
+ Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'.
+
+
+
+
+ Type has multiple constructors annotated with JsonConstructorAttribute.
+
+
Não gerou metadados de serialização para o tipo '{0}'.
diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ru.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ru.xlf
index cfe41af9643dd..66b70494f1544 100644
--- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ru.xlf
+++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ru.xlf
@@ -22,6 +22,16 @@
Дублирующееся имя типа.
+
+
+ Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'.
+
+
+
+
+ Type has multiple constructors annotated with JsonConstructorAttribute.
+
+
Метаданные сериализации для типа "{0}" не сформированы.
diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.tr.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.tr.xlf
index 3cb4589cff743..0334244bca30a 100644
--- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.tr.xlf
+++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.tr.xlf
@@ -22,6 +22,16 @@
Yinelenen tür adı.
+
+
+ Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'.
+
+
+
+
+ Type has multiple constructors annotated with JsonConstructorAttribute.
+
+
'{0}' türü için serileştirme meta verileri oluşturulmadı.
diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hans.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hans.xlf
index bd0e02092b849..fde4989102089 100644
--- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hans.xlf
+++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hans.xlf
@@ -22,6 +22,16 @@
重复的类型名称。
+
+
+ Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'.
+
+
+
+
+ Type has multiple constructors annotated with JsonConstructorAttribute.
+
+
未生成类型 '{0}' 的序列化元数据。
diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hant.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hant.xlf
index 756866eb4f6e8..2928ee14c10c9 100644
--- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hant.xlf
+++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hant.xlf
@@ -22,6 +22,16 @@
重複類型名稱。
+
+
+ Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'.
+
+
+
+
+ Type has multiple constructors annotated with JsonConstructorAttribute.
+
+
未產生類型 '{0}' 的序列化中繼資料。
diff --git a/src/libraries/System.Text.Json/gen/System.Text.Json.SourceGeneration.csproj b/src/libraries/System.Text.Json/gen/System.Text.Json.SourceGeneration.csproj
index 008a5b221895d..0bdc4da423a85 100644
--- a/src/libraries/System.Text.Json/gen/System.Text.Json.SourceGeneration.csproj
+++ b/src/libraries/System.Text.Json/gen/System.Text.Json.SourceGeneration.csproj
@@ -1,4 +1,4 @@
-
+
netstandard2.0
false
@@ -28,7 +28,8 @@
-
+
+
@@ -42,6 +43,7 @@
+
diff --git a/src/libraries/System.Text.Json/gen/TypeGenerationSpec.cs b/src/libraries/System.Text.Json/gen/TypeGenerationSpec.cs
index 9241d57c1d593..4c2eb61e27d66 100644
--- a/src/libraries/System.Text.Json/gen/TypeGenerationSpec.cs
+++ b/src/libraries/System.Text.Json/gen/TypeGenerationSpec.cs
@@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
+using System.Reflection;
using System.Text.Json.Reflection;
using System.Text.Json.Serialization;
@@ -45,6 +46,8 @@ internal class TypeGenerationSpec
public List? PropertyGenSpecList { get; private set; }
+ public ParameterGenerationSpec[]? CtorParamGenSpecArray { get; private set; }
+
public CollectionType CollectionType { get; private set; }
public TypeGenerationSpec? CollectionKeyTypeMetadata { get; private set; }
@@ -96,6 +99,7 @@ public void Initialize(
ClassType classType,
JsonNumberHandling? numberHandling,
List? propertyGenSpecList,
+ ParameterGenerationSpec[]? ctorParamGenSpecArray,
CollectionType collectionType,
TypeGenerationSpec? collectionKeyTypeMetadata,
TypeGenerationSpec? collectionValueTypeMetadata,
@@ -114,6 +118,7 @@ public void Initialize(
CanBeNull = !IsValueType || nullableUnderlyingTypeMetadata != null;
NumberHandling = numberHandling;
PropertyGenSpecList = propertyGenSpecList;
+ CtorParamGenSpecArray = ctorParamGenSpecArray;
CollectionType = collectionType;
CollectionKeyTypeMetadata = collectionKeyTypeMetadata;
CollectionValueTypeMetadata = collectionValueTypeMetadata;
@@ -210,7 +215,9 @@ private bool FastPathIsSupported()
{
foreach (PropertyGenerationSpec property in PropertyGenSpecList)
{
- if (property.TypeGenerationSpec.Type.IsObjectType())
+ if (property.TypeGenerationSpec.Type.IsObjectType() ||
+ property.NumberHandling == JsonNumberHandling.AllowNamedFloatingPointLiterals ||
+ property.NumberHandling == JsonNumberHandling.WriteAsString)
{
return false;
}
diff --git a/src/libraries/System.Text.Json/ref/System.Text.Json.cs b/src/libraries/System.Text.Json/ref/System.Text.Json.cs
index 74e702221a1ab..97da0d7f7faa2 100644
--- a/src/libraries/System.Text.Json/ref/System.Text.Json.cs
+++ b/src/libraries/System.Text.Json/ref/System.Text.Json.cs
@@ -991,7 +991,7 @@ public static partial class JsonMetadataServices
public static JsonTypeInfo CreateIReadOnlyDictionaryInfo(System.Text.Json.JsonSerializerOptions options, System.Func createObjectFunc, JsonTypeInfo keyInfo, JsonTypeInfo valueInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.Generic.IReadOnlyDictionary where TKey : notnull { throw null; }
public static JsonTypeInfo CreateISetInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, System.Text.Json.Serialization.Metadata.JsonTypeInfo elementInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.Generic.ISet { throw null; }
public static System.Text.Json.Serialization.Metadata.JsonTypeInfo CreateListInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, System.Text.Json.Serialization.Metadata.JsonTypeInfo elementInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.Generic.List { throw null; }
- public static System.Text.Json.Serialization.Metadata.JsonTypeInfo CreateObjectInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, System.Func? propInitFunc, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where T : notnull { throw null; }
+ public static System.Text.Json.Serialization.Metadata.JsonTypeInfo CreateObjectInfo(System.Text.Json.JsonSerializerOptions options, System.Text.Json.Serialization.Metadata.JsonObjectInfoValues objectInfo) where T : notnull { throw null; }
public static System.Text.Json.Serialization.Metadata.JsonPropertyInfo CreatePropertyInfo(System.Text.Json.JsonSerializerOptions options, bool isProperty, bool isPublic, bool isVirtual, System.Type declaringType, System.Text.Json.Serialization.Metadata.JsonTypeInfo propertyTypeInfo, System.Text.Json.Serialization.JsonConverter? converter, System.Func