Skip to content

Commit

Permalink
Number handling with converters (#57525)
Browse files Browse the repository at this point in the history
Co-authored-by: Layomi Akinrinade <laakinri@microsoft.com>
  • Loading branch information
steveharter and layomia committed Aug 17, 2021
1 parent e9e9f10 commit d6ea158
Show file tree
Hide file tree
Showing 6 changed files with 262 additions and 84 deletions.
7 changes: 2 additions & 5 deletions src/libraries/System.Text.Json/src/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -518,11 +518,8 @@
<data name="IgnoreConditionOnValueTypeInvalid" xml:space="preserve">
<value>The ignore condition 'JsonIgnoreCondition.WhenWritingNull' is not valid on value-type member '{0}' on type '{1}'. Consider using 'JsonIgnoreCondition.WhenWritingDefault'.</value>
</data>
<data name="NumberHandlingConverterMustBeBuiltIn" xml:space="preserve">
<value>'JsonNumberHandlingAttribute' cannot be placed on a property, field, or type that is handled by a custom converter. See usage(s) of converter '{0}' on type '{1}'.</value>
</data>
<data name="NumberHandlingOnPropertyTypeMustBeNumberOrCollection" xml:space="preserve">
<value>When 'JsonNumberHandlingAttribute' is placed on a property or field, the property or field must be a number or a collection of numbers. See member '{0}' on type '{1}'.</value>
<data name="NumberHandlingOnPropertyInvalid" xml:space="preserve">
<value>'JsonNumberHandlingAttribute' is only valid on a number or a collection of numbers when applied to a property or field. See member '{0}' on type '{1}'.</value>
</data>
<data name="ConverterCanConvertMultipleTypes" xml:space="preserve">
<value>The converter '{0}' handles type '{1}' but is being asked to convert type '{2}'. Either create a separate converter for type '{2}' or change the converter's 'CanConvert' method to only return 'true' for a single type.</value>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ internal bool TryRead(ref Utf8JsonReader reader, Type typeToConvert, JsonSeriali
// For performance, only perform validation on internal converters on debug builds.
if (IsInternalConverter)
{
if (state.Current.NumberHandling != null)
if (state.Current.NumberHandling != null && IsInternalConverterForNumberType)
{
value = ReadNumberWithCustomHandling(ref reader, state.Current.NumberHandling.Value, options);
}
Expand All @@ -186,7 +186,7 @@ internal bool TryRead(ref Utf8JsonReader reader, Type typeToConvert, JsonSeriali
int originalPropertyDepth = reader.CurrentDepth;
long originalPropertyBytesConsumed = reader.BytesConsumed;

if (state.Current.NumberHandling != null)
if (state.Current.NumberHandling != null && IsInternalConverterForNumberType)
{
value = ReadNumberWithCustomHandling(ref reader, state.Current.NumberHandling.Value, options);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -271,34 +271,32 @@ private bool NumberHandingIsApplicable()
return true;
}

Type potentialNumberType;
if (!ConverterBase.IsInternalConverter ||
((ConverterStrategy.Enumerable | ConverterStrategy.Dictionary) & ConverterStrategy) == 0)
{
return false;
potentialNumberType = DeclaredPropertyType;
}

Type? elementType = ConverterBase.ElementType;
Debug.Assert(elementType != null);

elementType = Nullable.GetUnderlyingType(elementType) ?? elementType;

if (elementType == typeof(byte) ||
elementType == typeof(decimal) ||
elementType == typeof(double) ||
elementType == typeof(short) ||
elementType == typeof(int) ||
elementType == typeof(long) ||
elementType == typeof(sbyte) ||
elementType == typeof(float) ||
elementType == typeof(ushort) ||
elementType == typeof(uint) ||
elementType == typeof(ulong) ||
elementType == JsonTypeInfo.ObjectType)
else
{
return true;
Debug.Assert(ConverterBase.ElementType != null);
potentialNumberType = ConverterBase.ElementType;
}

return false;
potentialNumberType = Nullable.GetUnderlyingType(potentialNumberType) ?? potentialNumberType;

return potentialNumberType == typeof(byte) ||
potentialNumberType == typeof(decimal) ||
potentialNumberType == typeof(double) ||
potentialNumberType == typeof(short) ||
potentialNumberType == typeof(int) ||
potentialNumberType == typeof(long) ||
potentialNumberType == typeof(sbyte) ||
potentialNumberType == typeof(float) ||
potentialNumberType == typeof(ushort) ||
potentialNumberType == typeof(uint) ||
potentialNumberType == typeof(ulong) ||
potentialNumberType == JsonTypeInfo.ObjectType;
}

internal static TAttribute? GetAttribute<TAttribute>(MemberInfo memberInfo) where TAttribute : Attribute
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,21 +239,10 @@ public static void ThrowInvalidOperationException_IgnoreConditionOnValueTypeInva
public static void ThrowInvalidOperationException_NumberHandlingOnPropertyInvalid(JsonPropertyInfo jsonPropertyInfo)
{
MemberInfo? memberInfo = jsonPropertyInfo.MemberInfo;
Debug.Assert(memberInfo != null);
Debug.Assert(!jsonPropertyInfo.IsForTypeInfo);

if (!jsonPropertyInfo.ConverterBase.IsInternalConverter)
{
throw new InvalidOperationException(SR.Format(
SR.NumberHandlingConverterMustBeBuiltIn,
jsonPropertyInfo.ConverterBase.GetType(),
jsonPropertyInfo.IsForTypeInfo ? jsonPropertyInfo.DeclaredPropertyType : memberInfo!.DeclaringType));
}

// This exception is only thrown for object properties.
Debug.Assert(!jsonPropertyInfo.IsForTypeInfo && memberInfo != null);
throw new InvalidOperationException(SR.Format(
SR.NumberHandlingOnPropertyTypeMustBeNumberOrCollection,
memberInfo.Name,
memberInfo.DeclaringType));
throw new InvalidOperationException(SR.Format(SR.NumberHandlingOnPropertyInvalid, memberInfo.Name, memberInfo.DeclaringType));
}

[DoesNotReturn]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1880,7 +1880,7 @@ public override int Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSeri

public override void Write(Utf8JsonWriter writer, int value, JsonSerializerOptions options)
{
throw new NotImplementedException();
throw new NotImplementedException("Converter was called");
}
}

Expand Down
Loading

0 comments on commit d6ea158

Please sign in to comment.