<value>The JSON property name for '{0}.{1}' cannot be null.</value>
</data>
<data name="SerializationDataExtensionPropertyInvalid" xml:space="preserve">
- <value>The data extension property '{0}.{1}' is invalid. It must implement 'IDictionary<string, JsonElement>' or 'IDictionary<string, object>', or be 'JsonObject'.</value>
+ <value>The extension data property '{0}.{1}' is invalid. It must implement 'IDictionary<string, JsonElement>' or 'IDictionary<string, object>', or be 'JsonObject'.</value>
</data>
<data name="SerializationDuplicateTypeAttribute" xml:space="preserve">
<value>The type '{0}' cannot have more than one member that has the attribute '{1}'.</value>
using System.Diagnostics;
using System.Text.Json.Nodes;
+using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json.Serialization.Converters
{
internal sealed class JsonObjectConverter : JsonConverter<JsonObject>
{
- internal override object CreateObject(JsonSerializerOptions options)
+ internal override void ConfigureJsonTypeInfo(JsonTypeInfo jsonTypeInfo, JsonSerializerOptions options)
{
- return new JsonObject(options.GetNodeOptions());
+ jsonTypeInfo.CreateObjectForExtensionDataProperty = () => new JsonObject(options.GetNodeOptions());
}
internal override void ReadElementAndSetProperty(
JsonObject jObject = (JsonObject)obj;
Debug.Assert(value == null || value is JsonNode);
- JsonNode? jNodeValue = (JsonNode?)value;
+ JsonNode? jNodeValue = value;
jObject[propertyName] = jNodeValue;
}
{
Debug.Assert(jsonPropertyInfo == state.Current.JsonTypeInfo.ExtensionDataProperty);
state.Current.JsonPropertyNameAsString = dataExtKey;
- JsonSerializer.CreateDataExtensionProperty(obj, jsonPropertyInfo, options);
+ JsonSerializer.CreateExtensionDataProperty(obj, jsonPropertyInfo, options);
}
ReadPropertyValue(obj, ref state, ref tempReader, jsonPropertyInfo, useExtensionProperty);
{
Debug.Assert(jsonPropertyInfo == state.Current.JsonTypeInfo.ExtensionDataProperty);
- JsonSerializer.CreateDataExtensionProperty(obj, jsonPropertyInfo, options);
+ JsonSerializer.CreateExtensionDataProperty(obj, jsonPropertyInfo, options);
object extDictionary = jsonPropertyInfo.GetValueAsObject(obj)!;
if (extDictionary is IDictionary<string, JsonElement> dict)
/// <summary>
/// Used to support JsonObject as an extension property in a loosely-typed, trimmable manner.
/// </summary>
- internal virtual object CreateObject(JsonSerializerOptions options)
- {
- throw new InvalidOperationException(SR.NodeJsonObjectCustomConverterNotAllowedOnExtensionProperty);
- }
-
- /// <summary>
- /// Used to support JsonObject as an extension property in a loosely-typed, trimmable manner.
- /// </summary>
internal virtual void ReadElementAndSetProperty(
object obj,
string propertyName,
JsonSerializerOptions options,
ref ReadStack state)
{
- throw new InvalidOperationException(SR.NodeJsonObjectCustomConverterNotAllowedOnExtensionProperty);
+ Debug.Fail("Should not be reachable.");
+
+ throw new InvalidOperationException();
}
internal abstract JsonParameterInfo CreateJsonParameterInfo();
if (createExtensionProperty)
{
Debug.Assert(obj != null, "obj is null");
- CreateDataExtensionProperty(obj, dataExtProperty, options);
+ CreateExtensionDataProperty(obj, dataExtProperty, options);
}
jsonPropertyInfo = dataExtProperty;
return unescapedPropertyName;
}
- internal static void CreateDataExtensionProperty(
+ internal static void CreateExtensionDataProperty(
object obj,
JsonPropertyInfo jsonPropertyInfo,
JsonSerializerOptions options)
// Avoid a reference to the JsonNode type for trimming
if (jsonPropertyInfo.PropertyType.FullName == JsonTypeInfo.JsonObjectTypeName)
{
- extensionData = jsonPropertyInfo.EffectiveConverter.CreateObject(options);
+ ThrowHelper.ThrowInvalidOperationException_NodeJsonObjectCustomConverterNotAllowedOnExtensionProperty();
}
else
{
ThrowHelper.ThrowNotSupportedException_SerializationNotSupported(jsonPropertyInfo.PropertyType);
}
}
- else
- {
- extensionData = createObjectForExtensionDataProp();
- }
+ extensionData = createObjectForExtensionDataProp();
jsonPropertyInfo.SetExtensionDictionaryAsObject(obj, extensionData);
}
private protected abstract void SetCreateObject(Delegate? createObject);
private protected Func<object>? _createObject;
- internal Func<object>? CreateObjectForExtensionDataProperty { get; private protected set; }
+ internal Func<object>? CreateObjectForExtensionDataProperty { get; set; }
/// <summary>
/// Gets or sets a callback to be invoked before serialization occurs.
}
}
- internal virtual void Configure()
+ internal void Configure()
{
Debug.Assert(Monitor.IsEntered(_configureLock), "Configure called directly, use EnsureConfigured which locks this method");
Debug.Assert(PropertyInfoForTypeInfo.ConverterStrategy == Converter.ConverterStrategy,
$"ConverterStrategy from PropertyInfoForTypeInfo.ConverterStrategy ({PropertyInfoForTypeInfo.ConverterStrategy}) does not match converter's ({Converter.ConverterStrategy})");
- converter.ConfigureJsonTypeInfo(this, Options);
-
if (Kind == JsonTypeInfoKind.Object)
{
InitializePropertyCache();
}
CreateObjectForExtensionDataProperty = createObject;
- }
- [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
- Justification = "The ctor is marked as RequiresUnreferencedCode")]
- [UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode",
- Justification = "The ctor is marked RequiresDynamicCode.")]
- internal override void Configure()
- {
- base.Configure();
- Converter.ConfigureJsonTypeInfoUsingReflection(this, Options);
+ // Plug in any converter configuration -- should be run last.
+ converter.ConfigureJsonTypeInfo(this, options);
+ converter.ConfigureJsonTypeInfoUsingReflection(this, options);
}
[RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
{
PopulatePolymorphismMetadata();
MapInterfaceTypesToCallbacks();
+
+ // Plug in any converter configuration -- should be run last.
+ converter.ConfigureJsonTypeInfo(this, options);
}
/// <summary>
/// Creates serialization metadata for an object.
/// </summary>
- public SourceGenJsonTypeInfo(JsonSerializerOptions options, JsonObjectInfoValues<T> objectInfo) : this(GetConverter(objectInfo), options)
+ public SourceGenJsonTypeInfo(JsonSerializerOptions options, JsonObjectInfoValues<T> objectInfo) : base(GetConverter(objectInfo), options)
{
if (objectInfo.ObjectWithParameterizedConstructorCreator != null)
{
PropInitFunc = objectInfo.PropertyMetadataInitializer;
SerializeHandler = objectInfo.SerializeHandler;
NumberHandling = objectInfo.NumberHandling;
+ PopulatePolymorphismMetadata();
+ MapInterfaceTypesToCallbacks();
+
+ // Plug in any converter configuration -- should be run last.
+ Converter.ConfigureJsonTypeInfo(this, options);
}
/// <summary>
Func<JsonConverter<T>> converterCreator,
object? createObjectWithArgs = null,
object? addFunc = null)
- : this(new JsonMetadataServicesConverter<T>(converterCreator()), options)
+ : base(new JsonMetadataServicesConverter<T>(converterCreator()), options)
{
if (collectionInfo is null)
{
CreateObjectWithArgs = createObjectWithArgs;
AddMethodDelegate = addFunc;
CreateObject = collectionInfo.ObjectCreator;
+ PopulatePolymorphismMetadata();
+ MapInterfaceTypesToCallbacks();
+
+ // Plug in any converter configuration -- should be run last.
+ Converter.ConfigureJsonTypeInfo(this, options);
}
private static JsonConverter GetConverter(JsonObjectInfoValues<T> objectInfo)
}
[DoesNotReturn]
+ public static void ThrowInvalidOperationException_NodeJsonObjectCustomConverterNotAllowedOnExtensionProperty()
+ {
+ throw new InvalidOperationException(SR.NodeJsonObjectCustomConverterNotAllowedOnExtensionProperty);
+ }
+
+ [DoesNotReturn]
public static void ThrowNotSupportedException(ref ReadStack state, in Utf8JsonReader reader, NotSupportedException ex)
{
string message = ex.Message;
// 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.Linq;
using System.Reflection;
Assert.True(deserialized.E);
}
+
+ [Theory]
+ [InlineData(typeof(ICollection<string>))]
+ [InlineData(typeof(IList))]
+ [InlineData(typeof(IList<bool>))]
+ [InlineData(typeof(IDictionary))]
+ [InlineData(typeof(IDictionary<string, bool>))]
+ [InlineData(typeof(ISet<Guid>))]
+ public static void AbstractCollectionMetadata_SurfacesCreateObjectWhereApplicable(Type type)
+ {
+ var options = new JsonSerializerOptions();
+ var resolver = new DefaultJsonTypeInfoResolver();
+
+ JsonTypeInfo metadata = resolver.GetTypeInfo(type, options);
+ Assert.NotNull(metadata.CreateObject);
+ Assert.IsAssignableFrom(type, metadata.CreateObject());
+ }
+
private class ClassWithLargeParameterizedConstructor
{
public int A { get; set; }