Skip to content

Commit 11bfa9b

Browse files
authored
Tests for creating recursive types (#71721)
1 parent 0e30a6f commit 11bfa9b

File tree

1 file changed

+137
-0
lines changed

1 file changed

+137
-0
lines changed

src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/DefaultJsonTypeInfoResolverTests.JsonTypeInfo.cs

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -964,5 +964,142 @@ private class ClassWithExplicitOrderOfProperties
964964
[JsonPropertyOrder(-2)]
965965
public string A { get; set; }
966966
}
967+
968+
[Fact]
969+
public static void RecursiveTypeWithResolverResolvingOnlyThatType()
970+
{
971+
TestResolver resolver = new(ResolveTypeInfo);
972+
973+
JsonSerializerOptions options = new();
974+
options.TypeInfoResolver = resolver;
975+
976+
string json = JsonSerializer.Serialize(new RecursiveType() { Next = new RecursiveType() }, options);
977+
Assert.Equal("""{"Next":{"Next":null}}""", json);
978+
979+
RecursiveType deserialized = JsonSerializer.Deserialize<RecursiveType>(json, options);
980+
Assert.NotNull(deserialized);
981+
Assert.Equal(2, deserialized.Value);
982+
Assert.NotNull(deserialized.Next);
983+
Assert.Equal(1, deserialized.Next.Value);
984+
Assert.Null(deserialized.Next.Next);
985+
986+
static JsonTypeInfo? ResolveTypeInfo(Type type, JsonSerializerOptions options)
987+
{
988+
int value = 1;
989+
if (type == typeof(RecursiveType))
990+
{
991+
JsonTypeInfo<RecursiveType> ti = JsonTypeInfo.CreateJsonTypeInfo<RecursiveType>(options);
992+
ti.CreateObject = () => new RecursiveType();
993+
JsonPropertyInfo prop = ti.CreateJsonPropertyInfo(typeof(RecursiveType), "Next");
994+
prop.Get = (obj) => ((RecursiveType)obj).Next;
995+
prop.Set = (obj, val) =>
996+
{
997+
RecursiveType recursiveObj = (RecursiveType)obj;
998+
recursiveObj.Next = (RecursiveType)val;
999+
recursiveObj.Value = value++;
1000+
};
1001+
ti.Properties.Add(prop);
1002+
return ti;
1003+
}
1004+
1005+
return null;
1006+
}
1007+
}
1008+
1009+
[Fact]
1010+
public static void RecursiveTypeWithResolverResolvingOnlyThatTypeThrowsWhenPropertyOfDifferentType()
1011+
{
1012+
TestResolver resolver = new(ResolveTypeInfo);
1013+
1014+
JsonSerializerOptions options = new();
1015+
options.TypeInfoResolver = resolver;
1016+
1017+
Assert.Throws<NotSupportedException>(() => JsonSerializer.Serialize(new RecursiveType() { Next = new RecursiveType() }, options));
1018+
Assert.Throws<NotSupportedException>(() => JsonSerializer.Deserialize<RecursiveType>("""{"Next":{"Next":null}}""", options));
1019+
1020+
static JsonTypeInfo? ResolveTypeInfo(Type type, JsonSerializerOptions options)
1021+
{
1022+
if (type == typeof(RecursiveType))
1023+
{
1024+
JsonTypeInfo<RecursiveType> ti = JsonTypeInfo.CreateJsonTypeInfo<RecursiveType>(options);
1025+
ti.CreateObject = () => new RecursiveType();
1026+
{
1027+
JsonPropertyInfo prop = ti.CreateJsonPropertyInfo(typeof(RecursiveType), "Next");
1028+
prop.Get = (obj) => ((RecursiveType)obj).Next;
1029+
prop.Set = (obj, val) => ((RecursiveType)obj).Next = (RecursiveType)val;
1030+
ti.Properties.Add(prop);
1031+
}
1032+
{
1033+
JsonPropertyInfo prop = ti.CreateJsonPropertyInfo(typeof(int), "Value");
1034+
prop.Get = (obj) => ((RecursiveType)obj).Value;
1035+
prop.Set = (obj, val) => ((RecursiveType)obj).Value = (int)val;
1036+
ti.Properties.Add(prop);
1037+
}
1038+
1039+
return ti;
1040+
}
1041+
1042+
return null;
1043+
}
1044+
}
1045+
1046+
[Fact]
1047+
public static void RecursiveTypeWithResolverResolvingOnlyUsedTypes()
1048+
{
1049+
TestResolver resolver = new(ResolveTypeInfo);
1050+
1051+
JsonSerializerOptions options = new();
1052+
options.TypeInfoResolver = resolver;
1053+
1054+
RecursiveType obj = new RecursiveType()
1055+
{
1056+
Value = 13,
1057+
Next = new RecursiveType() { Value = 7 },
1058+
};
1059+
string json = JsonSerializer.Serialize(obj, options);
1060+
Assert.Equal("""{"Next":{"Next":null,"Value":7},"Value":13}""", json);
1061+
1062+
RecursiveType deserialized = JsonSerializer.Deserialize<RecursiveType>(json, options);
1063+
Assert.NotNull(deserialized);
1064+
Assert.Equal(13, deserialized.Value);
1065+
Assert.NotNull(deserialized.Next);
1066+
Assert.Equal(7, deserialized.Next.Value);
1067+
Assert.Null(deserialized.Next.Next);
1068+
1069+
static JsonTypeInfo? ResolveTypeInfo(Type type, JsonSerializerOptions options)
1070+
{
1071+
if (type == typeof(RecursiveType))
1072+
{
1073+
JsonTypeInfo<RecursiveType> ti = JsonTypeInfo.CreateJsonTypeInfo<RecursiveType>(options);
1074+
ti.CreateObject = () => new RecursiveType();
1075+
{
1076+
JsonPropertyInfo prop = ti.CreateJsonPropertyInfo(typeof(RecursiveType), "Next");
1077+
prop.Get = (obj) => ((RecursiveType)obj).Next;
1078+
prop.Set = (obj, val) => ((RecursiveType)obj).Next = (RecursiveType)val;
1079+
ti.Properties.Add(prop);
1080+
}
1081+
{
1082+
JsonPropertyInfo prop = ti.CreateJsonPropertyInfo(typeof(int), "Value");
1083+
prop.Get = (obj) => ((RecursiveType)obj).Value;
1084+
prop.Set = (obj, val) => ((RecursiveType)obj).Value = (int)val;
1085+
ti.Properties.Add(prop);
1086+
}
1087+
return ti;
1088+
}
1089+
1090+
if (type == typeof(int))
1091+
{
1092+
return JsonTypeInfo.CreateJsonTypeInfo<int>(options);
1093+
}
1094+
1095+
return null;
1096+
}
1097+
}
1098+
1099+
private class RecursiveType
1100+
{
1101+
public int Value { get; set; }
1102+
public RecursiveType? Next { get; set; }
1103+
}
9671104
}
9681105
}

0 commit comments

Comments
 (0)