// Some of the validation is done during construction (i.e. validity of JsonConverter, inner types etc.)
// therefore we need to unwrap TargetInvocationException for better user experience
ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
- throw ex.InnerException;
+ throw null!;
}
#endif
}
public static JsonTypeInfo<T> CreateValueInfo<T>(JsonSerializerOptions options, JsonConverter converter)
{
JsonTypeInfo<T> info = new SourceGenJsonTypeInfo<T>(converter, options);
- info.PropertyInfoForTypeInfo = CreateJsonPropertyInfoForClassInfo(typeof(T), info, converter, options);
return info;
}
-
- internal static JsonPropertyInfo CreateJsonPropertyInfoForClassInfo(
- Type type,
- JsonTypeInfo typeInfo,
- JsonConverter converter,
- JsonSerializerOptions options)
- {
- JsonPropertyInfo propertyInfo = converter.CreateJsonPropertyInfo();
- propertyInfo.InitializeForTypeInfo(type, typeInfo, converter, options);
- return propertyInfo;
- }
}
}
_isConfigured = true;
}
- internal virtual void GetPolicies(JsonIgnoreCondition? ignoreCondition)
+ internal void GetPolicies(JsonIgnoreCondition? ignoreCondition)
{
- if (!IsForTypeInfo)
- {
- Debug.Assert(MemberInfo != null);
- DetermineSerializationCapabilities(ignoreCondition);
- DeterminePropertyName();
- DetermineIgnoreCondition(ignoreCondition);
-
- JsonPropertyOrderAttribute? orderAttr = GetAttribute<JsonPropertyOrderAttribute>(MemberInfo);
- if (orderAttr != null)
- {
- Order = orderAttr.Order;
- }
+ Debug.Assert(MemberInfo != null);
+ DetermineSerializationCapabilities(ignoreCondition);
+ DeterminePropertyName();
+ DetermineIgnoreCondition(ignoreCondition);
- JsonNumberHandlingAttribute? attribute = GetAttribute<JsonNumberHandlingAttribute>(MemberInfo);
- NumberHandling = attribute?.Handling;
+ JsonPropertyOrderAttribute? orderAttr = GetAttribute<JsonPropertyOrderAttribute>(MemberInfo);
+ if (orderAttr != null)
+ {
+ Order = orderAttr.Order;
}
+
+ JsonNumberHandlingAttribute? attribute = GetAttribute<JsonNumberHandlingAttribute>(MemberInfo);
+ NumberHandling = attribute?.Handling;
}
private void DeterminePropertyName()
internal bool HasGetter { get; set; }
internal bool HasSetter { get; set; }
- internal virtual void Initialize(
+ internal abstract void Initialize(
Type parentClassType,
Type declaredPropertyType,
ConverterStrategy converterStrategy,
bool isVirtual,
JsonConverter converter,
JsonIgnoreCondition? ignoreCondition,
- JsonNumberHandling? parentTypeNumberHandling,
- JsonSerializerOptions options)
- {
- Debug.Assert(converter != null);
-
- DeclaringType = parentClassType;
- PropertyType = declaredPropertyType;
- ConverterStrategy = converterStrategy;
- MemberInfo = memberInfo;
- IsVirtual = isVirtual;
- ConverterBase = converter;
- Options = options;
- }
-
- internal abstract void InitializeForTypeInfo(
- Type declaredType,
- JsonTypeInfo runtimeTypeInfo,
- JsonConverter converter,
- JsonSerializerOptions options);
+ JsonSerializerOptions options,
+ JsonTypeInfo? jsonTypeInfo = null);
internal bool IgnoreDefaultValuesOnRead { get; private set; }
internal bool IgnoreDefaultValuesOnWrite { get; private set; }
internal Type DeclaringType { get; set; } = null!;
- internal MemberInfo? MemberInfo { get; private set; }
+ internal MemberInfo? MemberInfo { get; set; }
internal JsonTypeInfo JsonTypeInfo
{
bool isVirtual,
JsonConverter converter,
JsonIgnoreCondition? ignoreCondition,
- JsonNumberHandling? parentTypeNumberHandling,
- JsonSerializerOptions options)
+ JsonSerializerOptions options,
+ JsonTypeInfo? jsonTypeInfo = null)
{
- base.Initialize(
- parentClassType,
- declaredPropertyType,
- converterStrategy,
- memberInfo,
- isVirtual,
- converter,
- ignoreCondition,
- parentTypeNumberHandling,
- options);
-
- switch (memberInfo)
+ Debug.Assert(converter != null);
+
+ PropertyType = declaredPropertyType;
+ ConverterStrategy = converterStrategy;
+ if (jsonTypeInfo != null)
{
- case PropertyInfo propertyInfo:
- {
- bool useNonPublicAccessors = GetAttribute<JsonIncludeAttribute>(propertyInfo) != null;
+ JsonTypeInfo = jsonTypeInfo;
+ }
- MethodInfo? getMethod = propertyInfo.GetMethod;
- if (getMethod != null && (getMethod.IsPublic || useNonPublicAccessors))
- {
- HasGetter = true;
- Get = options.MemberAccessorStrategy.CreatePropertyGetter<T>(propertyInfo);
- }
+ ConverterBase = converter;
+ Options = options;
+ DeclaringType = parentClassType;
+ MemberInfo = memberInfo;
+ IsVirtual = isVirtual;
- MethodInfo? setMethod = propertyInfo.SetMethod;
- if (setMethod != null && (setMethod.IsPublic || useNonPublicAccessors))
+ if (memberInfo != null)
+ {
+ switch (memberInfo)
+ {
+ case PropertyInfo propertyInfo:
{
- HasSetter = true;
- Set = options.MemberAccessorStrategy.CreatePropertySetter<T>(propertyInfo);
- }
+ bool useNonPublicAccessors = GetAttribute<JsonIncludeAttribute>(propertyInfo) != null;
- MemberType = MemberTypes.Property;
+ MethodInfo? getMethod = propertyInfo.GetMethod;
+ if (getMethod != null && (getMethod.IsPublic || useNonPublicAccessors))
+ {
+ HasGetter = true;
+ Get = options.MemberAccessorStrategy.CreatePropertyGetter<T>(propertyInfo);
+ }
- break;
- }
+ MethodInfo? setMethod = propertyInfo.SetMethod;
+ if (setMethod != null && (setMethod.IsPublic || useNonPublicAccessors))
+ {
+ HasSetter = true;
+ Set = options.MemberAccessorStrategy.CreatePropertySetter<T>(propertyInfo);
+ }
- case FieldInfo fieldInfo:
- {
- Debug.Assert(fieldInfo.IsPublic);
+ MemberType = MemberTypes.Property;
- HasGetter = true;
- Get = options.MemberAccessorStrategy.CreateFieldGetter<T>(fieldInfo);
+ break;
+ }
- if (!fieldInfo.IsInitOnly)
+ case FieldInfo fieldInfo:
{
- HasSetter = true;
- Set = options.MemberAccessorStrategy.CreateFieldSetter<T>(fieldInfo);
- }
+ Debug.Assert(fieldInfo.IsPublic);
- MemberType = MemberTypes.Field;
+ HasGetter = true;
+ Get = options.MemberAccessorStrategy.CreateFieldGetter<T>(fieldInfo);
- break;
- }
+ if (!fieldInfo.IsInitOnly)
+ {
+ HasSetter = true;
+ Set = options.MemberAccessorStrategy.CreateFieldSetter<T>(fieldInfo);
+ }
- default:
- {
- IsForTypeInfo = true;
- HasGetter = true;
- HasSetter = true;
+ MemberType = MemberTypes.Field;
- break;
- }
- }
+ break;
+ }
- _converterIsExternalAndPolymorphic = !converter.IsInternalConverter && PropertyType != converter.TypeToConvert;
- PropertyTypeCanBeNull = PropertyType.CanBeNull();
- _propertyTypeEqualsTypeToConvert = typeof(T) == PropertyType;
+ default:
+ {
+ Debug.Fail($"Invalid memberInfo type: {memberInfo.GetType().FullName}");
+ break;
+ }
+ }
+
+ // TODO (perf): can we pre-compute some of these values during source gen?
+ _converterIsExternalAndPolymorphic = !converter.IsInternalConverter && PropertyType != converter.TypeToConvert;
+ PropertyTypeCanBeNull = PropertyType.CanBeNull();
+ _propertyTypeEqualsTypeToConvert = typeof(T) == PropertyType;
- GetPolicies(ignoreCondition);
+ GetPolicies(ignoreCondition);
+ }
+ else
+ {
+ IsForTypeInfo = true;
+ HasGetter = true;
+ HasSetter = true;
+ }
}
internal void InitializeForSourceGen(JsonSerializerOptions options, JsonPropertyInfoValues<T> propertyInfo)
}
}
- /// <summary>
- /// Create a <see cref="JsonPropertyInfo"/> for a given Type.
- /// See <seealso cref="JsonTypeInfo.PropertyInfoForTypeInfo"/>.
- /// </summary>
- internal override void InitializeForTypeInfo(
- Type declaredType,
- JsonTypeInfo runtimeTypeInfo,
- JsonConverter converter,
- JsonSerializerOptions options)
- {
- PropertyType = declaredType;
- ConverterStrategy = converter.ConverterStrategy;
- JsonTypeInfo = runtimeTypeInfo;
- ConverterBase = converter;
- Options = options;
- IsForTypeInfo = true;
- HasGetter = true;
- HasSetter = true;
- // TODO (perf): can we pre-compute some of these values during source gen?
- _converterIsExternalAndPolymorphic = !converter.IsInternalConverter && declaredType != converter.TypeToConvert;
- PropertyTypeCanBeNull = declaredType.CanBeNull();
- _propertyTypeEqualsTypeToConvert = typeof(T) == declaredType;
- }
-
internal override JsonConverter ConverterBase
{
get
bool isVirtual,
JsonConverter converter,
JsonSerializerOptions options,
- JsonNumberHandling? parentTypeNumberHandling = null,
- JsonIgnoreCondition? ignoreCondition = null)
+ JsonIgnoreCondition? ignoreCondition = null,
+ JsonTypeInfo? jsonTypeInfo = null)
{
// Create the JsonPropertyInfo instance.
JsonPropertyInfo jsonPropertyInfo = converter.CreateJsonPropertyInfo();
isVirtual,
converter,
ignoreCondition,
- parentTypeNumberHandling,
- options);
+ options,
+ jsonTypeInfo);
return jsonPropertyInfo;
}
private static JsonPropertyInfo CreatePropertyInfoForTypeInfo(
Type declaredPropertyType,
JsonConverter converter,
- JsonNumberHandling? numberHandling,
- JsonSerializerOptions options)
+ JsonSerializerOptions options,
+ JsonTypeInfo? jsonTypeInfo = null)
{
JsonPropertyInfo jsonPropertyInfo = CreateProperty(
declaredPropertyType: declaredPropertyType,
memberInfo: null, // Not a real property so this is null.
parentClassType: ObjectType, // a dummy value (not used)
isVirtual: false,
- converter,
- options,
- parentTypeNumberHandling: numberHandling);
+ converter: converter,
+ options: options,
+ jsonTypeInfo: jsonTypeInfo);
Debug.Assert(jsonPropertyInfo.IsForTypeInfo);
/// TypeInfo (for the cases mentioned above). In addition, methods that have a JsonPropertyInfo argument would also likely
/// need to add an argument for JsonTypeInfo.
/// </remarks>
- internal JsonPropertyInfo PropertyInfoForTypeInfo { get; set; }
+ internal JsonPropertyInfo PropertyInfoForTypeInfo { get; private set; }
/// <summary>
/// Returns a helper class used for computing the default value.
internal JsonNumberHandling? NumberHandling { get; set; }
- internal JsonTypeInfo()
- {
- Debug.Assert(false, "This constructor should not be called.");
- }
-
- internal JsonTypeInfo(Type type, JsonSerializerOptions options!!)
- {
- Type = type;
- Options = options;
- // Setting this option is deferred to the initialization methods of the various metadada info types.
- PropertyInfoForTypeInfo = null!;
- }
-
internal JsonTypeInfo(Type type, JsonConverter converter, JsonSerializerOptions options)
{
Type = type;
Options = options;
- PropertyInfoForTypeInfo = CreatePropertyInfoForTypeInfo(Type, converter, NumberHandling, Options);
+ PropertyInfoForTypeInfo = CreatePropertyInfoForTypeInfo(Type, converter, Options, this);
ElementType = converter.ElementType;
switch (PropertyInfoForTypeInfo.ConverterStrategy)
{
private Action<Utf8JsonWriter, T>? _serialize;
- internal JsonTypeInfo(Type type, JsonSerializerOptions options) :
- base(type, options)
- { }
-
internal JsonTypeInfo(JsonConverter converter, JsonSerializerOptions options)
: base(typeof(T), converter, options)
{ }
- internal JsonTypeInfo()
- {
- Debug.Assert(false, "This constructor should not be called.");
- }
-
/// <summary>
/// Serializes an instance of <typeparamref name="T"/> using
/// <see cref="JsonSourceGenerationOptionsAttribute"/> values specified at design time.
ThrowHelper.ThrowInvalidOperationException_SerializationDuplicateTypeAttribute(Type, typeof(JsonExtensionDataAttribute));
}
- JsonPropertyInfo jsonPropertyInfo = AddProperty(memberInfo, memberType, declaringType, isVirtual, typeNumberHandling, Options);
+ JsonPropertyInfo jsonPropertyInfo = AddProperty(memberInfo, memberType, declaringType, isVirtual, Options);
Debug.Assert(jsonPropertyInfo.NameAsString != null);
if (hasExtensionAttribute)
Type memberType,
Type parentClassType,
bool isVirtual,
- JsonNumberHandling? parentTypeNumberHandling,
JsonSerializerOptions options)
{
JsonIgnoreCondition? ignoreCondition = JsonPropertyInfo.GetAttribute<JsonIgnoreAttribute>(memberInfo)?.Condition;
isVirtual,
converter,
options,
- parentTypeNumberHandling,
ignoreCondition);
}
/// Creates serialization metadata for a type using a simple converter.
/// </summary>
public SourceGenJsonTypeInfo(JsonConverter converter, JsonSerializerOptions options)
- : base(typeof(T), options)
+ : base(converter, options)
{
- ElementType = converter.ElementType;
}
/// <summary>
/// Creates serialization metadata for an object.
/// </summary>
- public SourceGenJsonTypeInfo(JsonSerializerOptions options, JsonObjectInfoValues<T> objectInfo) : base(typeof(T), options)
+ public SourceGenJsonTypeInfo(JsonSerializerOptions options, JsonObjectInfoValues<T> objectInfo) : base(GetConverter(objectInfo), options)
{
-#pragma warning disable CS8714
- // The type cannot be used as type parameter in the generic type or method.
- // Nullability of type argument doesn't match 'notnull' constraint.
- JsonConverter converter;
-
if (objectInfo.ObjectWithParameterizedConstructorCreator != null)
{
- converter = new JsonMetadataServicesConverter<T>(
- () => new LargeObjectWithParameterizedConstructorConverter<T>(),
- ConverterStrategy.Object);
CreateObjectWithArgs = objectInfo.ObjectWithParameterizedConstructorCreator;
CtorParamInitFunc = objectInfo.ConstructorParameterMetadataInitializer;
}
else
{
- converter = new JsonMetadataServicesConverter<T>(() => new ObjectDefaultConverter<T>(), ConverterStrategy.Object);
SetCreateObjectFunc(objectInfo.ObjectCreator);
}
-#pragma warning restore CS8714
+
PropInitFunc = objectInfo.PropertyMetadataInitializer;
- ElementType = converter.ElementType;
SerializeHandler = objectInfo.SerializeHandler;
- PropertyInfoForTypeInfo = JsonMetadataServices.CreateJsonPropertyInfoForClassInfo(typeof(T), this, converter, Options);
NumberHandling = objectInfo.NumberHandling;
}
Func<JsonConverter<T>> converterCreator,
object? createObjectWithArgs = null,
object? addFunc = null)
- : base(typeof(T), options)
+ : base(GetConverter(collectionInfo, converterCreator), options)
{
- ConverterStrategy strategy = collectionInfo.KeyInfo == null ? ConverterStrategy.Enumerable : ConverterStrategy.Dictionary;
- JsonConverter<T> converter = new JsonMetadataServicesConverter<T>(converterCreator, strategy);
-
- KeyType = converter.KeyType;
- ElementType = converter.ElementType;
KeyTypeInfo = collectionInfo.KeyInfo;
ElementTypeInfo = collectionInfo.ElementInfo ?? throw new ArgumentNullException(nameof(collectionInfo.ElementInfo));
NumberHandling = collectionInfo.NumberHandling;
- PropertyInfoForTypeInfo = JsonMetadataServices.CreateJsonPropertyInfoForClassInfo(typeof(T), this, converter, options);
SerializeHandler = collectionInfo.SerializeHandler;
CreateObjectWithArgs = createObjectWithArgs;
AddMethodDelegate = addFunc;
SetCreateObjectFunc(collectionInfo.ObjectCreator);
}
+ private static JsonConverter GetConverter(JsonObjectInfoValues<T> objectInfo)
+ {
+#pragma warning disable CS8714
+ // The type cannot be used as type parameter in the generic type or method.
+ // Nullability of type argument doesn't match 'notnull' constraint.
+ if (objectInfo.ObjectWithParameterizedConstructorCreator != null)
+ {
+ return new JsonMetadataServicesConverter<T>(
+ () => new LargeObjectWithParameterizedConstructorConverter<T>(),
+ ConverterStrategy.Object);
+ }
+ else
+ {
+ return new JsonMetadataServicesConverter<T>(() => new ObjectDefaultConverter<T>(), ConverterStrategy.Object);
+ }
+#pragma warning restore CS8714
+ }
+
+ private static JsonConverter GetConverter(JsonCollectionInfoValues<T> collectionInfo, Func<JsonConverter<T>> converterCreator)
+ {
+ ConverterStrategy strategy = collectionInfo.KeyInfo == null ? ConverterStrategy.Enumerable : ConverterStrategy.Dictionary;
+ return new JsonMetadataServicesConverter<T>(converterCreator, strategy);
+ }
+
internal override void LateAddProperties()
{
AddPropertiesUsingSourceGenInfo();