Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

Commit

Permalink
[System.Text.Json]Improve error output for unsupported scenarios in S…
Browse files Browse the repository at this point in the history
…ystem.Text.Json.Serialization (#38061)

* custom exception for parameterless constructors

* add polymorphic interface exception

* fix ReflectionMaterializer

* address PR feedback
  • Loading branch information
MarcoRossignoli authored and wtgodbe committed May 31, 2019
1 parent 6352388 commit 792eb85
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 1 deletion.
6 changes: 6 additions & 0 deletions src/System.Text.Json/src/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -371,4 +371,10 @@
<data name="JsonSerializerDoesNotSupportComments" xml:space="preserve">
<value>Comments cannot be stored when deserializing objects, only the Skip and Disallow comment handling modes are supported.</value>
</data>
<data name="DeserializeMissingParameterlessConstructor" xml:space="preserve">
<value>Deserialization of reference types without parameterless constructor is not supported. Type '{0}'</value>
</data>
<data name="DeserializePolymorphicInterface" xml:space="preserve">
<value>Deserialization of interface types is not supported. Type '{0}'</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,19 @@ private static void HandleStartObject(JsonSerializerOptions options, ref Utf8Jso
}

JsonClassInfo classInfo = state.Current.JsonClassInfo;

if (classInfo.CreateObject is null && classInfo.ClassType == ClassType.Object)
{
if (classInfo.Type.IsInterface)
{
ThrowHelper.ThrowInvalidOperationException_DeserializePolymorphicInterface(classInfo.Type);
}
else
{
ThrowHelper.ThrowInvalidOperationException_DeserializeMissingParameterlessConstructor(classInfo.Type);
}
}

state.Current.ReturnValue = classInfo.CreateObject();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ internal sealed class ReflectionMaterializer : ClassMaterializer
{
public override JsonClassInfo.ConstructorDelegate CreateConstructor(Type type)
{
Debug.Assert(type != null);
ConstructorInfo realMethod = type.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, binder: null, Type.EmptyTypes, modifiers: null);

if (realMethod == null && !type.IsValueType)
{
return null;
}

return () => Activator.CreateInstance(type);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,5 +122,17 @@ public static void ThrowInvalidOperationException_SerializationDataExtensionProp
{
throw new InvalidOperationException(SR.Format(SR.SerializationDataExtensionPropertyInvalidElement, jsonClassInfo.Type, jsonClassInfo.DataExtensionProperty.PropertyInfo.Name, invalidType));
}

[MethodImpl(MethodImplOptions.NoInlining)]
public static void ThrowInvalidOperationException_DeserializeMissingParameterlessConstructor(Type invalidType)
{
throw new NotSupportedException(SR.Format(SR.DeserializeMissingParameterlessConstructor, invalidType));
}

[MethodImpl(MethodImplOptions.NoInlining)]
public static void ThrowInvalidOperationException_DeserializePolymorphicInterface(Type invalidType)
{
throw new NotSupportedException(SR.Format(SR.DeserializePolymorphicInterface, invalidType));
}
}
}
19 changes: 19 additions & 0 deletions src/System.Text.Json/tests/Serialization/Object.ReadTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,25 @@ public static void ReadObjectFail()
Assert.Throws<JsonException>(() => JsonSerializer.Parse<object>("null."));
}

[Fact]
public static void ReadObjectFail_ReferenceTypeMissingParameterlessConstructor()
{
Assert.Throws<NotSupportedException>(() => JsonSerializer.Parse<PublicParameterizedConstructorTestClass>(@"{""Name"":""Name!""}"));
}

class PublicParameterizedConstructorTestClass
{
private readonly string _name;
public PublicParameterizedConstructorTestClass(string name)
{
_name = name;
}
public string Name
{
get { return _name; }
}
}

[Fact]
public static void ParseUntyped()
{
Expand Down
24 changes: 23 additions & 1 deletion src/System.Text.Json/tests/Serialization/PolymorphicTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,28 @@ public static void StaticAnalysisWithRelationship()
Assert.Equal(typeof(UsaCustomer), deserializedCustomer.GetType());
Assert.Equal(typeof(Address), deserializedCustomer.Address.GetType());
((Customer)deserializedCustomer).VerifyNonVirtual();
}
}

[Fact]
public static void PolymorphicInterface_NotSupported()
{
Assert.Throws<NotSupportedException>(() => JsonSerializer.Parse<MyClass>(@"{ ""Value"": ""A value"", ""Thing"": { ""Number"": 123 } }"));
}

class MyClass
{
public string Value { get; set; }
public IThing Thing { get; set; }
}

interface IThing
{
int Number { get; set; }
}

class MyThing : IThing
{
public int Number { get; set; }
}
}
}

0 comments on commit 792eb85

Please sign in to comment.