Add Guid serialization support. (dotnet/corefx#37529)
authorJeremy Kuhne <jkuhne@microsoft.com>
Wed, 15 May 2019 19:23:23 +0000 (12:23 -0700)
committerJosh Free <joshfree@users.noreply.github.com>
Wed, 15 May 2019 19:23:22 +0000 (12:23 -0700)
* Add Guid serialization support.

Add non IConvertable converters to dictionary for easier extensibility.

* Fix project ordering.

* Remove explicit static constructor

Commit migrated from https://github.com/dotnet/corefx/commit/797142155af425a7dd0581900ad4c9884c62e53b

src/libraries/System.Text.Json/src/System.Text.Json.csproj
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/DefaultConverters.cs
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/JsonValueConverterGuid.cs [new file with mode: 0644]
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.cs
src/libraries/System.Text.Json/tests/Serialization/TestClasses.SimpleTestClassWithNullables.cs
src/libraries/System.Text.Json/tests/Serialization/TestClasses.SimpleTestClassWithObjectArrays.cs
src/libraries/System.Text.Json/tests/Serialization/TestClasses.SimpleTestClassWithSimpleObject.cs

index 14f1ecb..15106dc 100644 (file)
@@ -59,6 +59,7 @@
     <Compile Include="System\Text\Json\Serialization\Converters\JsonValueConverterDecimal.cs" />
     <Compile Include="System\Text\Json\Serialization\Converters\JsonValueConverterDouble.cs" />
     <Compile Include="System\Text\Json\Serialization\Converters\JsonValueConverterEnum.cs" />
+    <Compile Include="System\Text\Json\Serialization\Converters\JsonValueConverterGuid.cs" />
     <Compile Include="System\Text\Json\Serialization\Converters\JsonValueConverterInt16.cs" />
     <Compile Include="System\Text\Json\Serialization\Converters\JsonValueConverterInt32.cs" />
     <Compile Include="System\Text\Json\Serialization\Converters\JsonValueConverterInt64.cs" />
index 0920a8a..bc33704 100644 (file)
@@ -2,12 +2,25 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+using System.Collections.Generic;
 using System.Reflection;
 
 namespace System.Text.Json.Serialization.Converters
 {
     internal static class DefaultConverters
     {
+        private static readonly Dictionary<Type, object> s_valueConverters = new Dictionary<Type, object>()
+        {
+            { typeof(DateTimeOffset), new JsonValueConverterDateTimeOffset() },
+            { typeof(Guid), new JsonValueConverterGuid() },
+            { typeof(JsonElement), new JsonValueConverterJsonElement() }
+        };
+
+        internal static bool IsValueConvertable(Type type)
+        {
+            return typeof(IConvertible).IsAssignableFrom(type) || s_valueConverters.ContainsKey(type);
+        }
+
         internal static object Create(Type type)
         {
             if (type.IsEnum)
@@ -54,19 +67,16 @@ namespace System.Text.Json.Serialization.Converters
                     return new JsonValueConverterString();
             }
 
-            if (type == typeof(DateTimeOffset))
+            if (s_valueConverters.TryGetValue(type, out object value))
             {
-                return new JsonValueConverterDateTimeOffset();
-            }
-            if (type == typeof(JsonElement))
-            {
-                return new JsonValueConverterJsonElement();
+                return value;
             }
+
             if (type == typeof(object))
             {
                 return new JsonValueConverterObject();
             }
-            
+
             return null;
         }
     }
diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/JsonValueConverterGuid.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/JsonValueConverterGuid.cs
new file mode 100644 (file)
index 0000000..5e5809c
--- /dev/null
@@ -0,0 +1,26 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Text.Json.Serialization.Policies;
+
+namespace System.Text.Json.Serialization.Converters
+{
+    internal sealed class JsonValueConverterGuid : JsonValueConverter<Guid>
+    {
+        public override bool TryRead(Type valueType, ref Utf8JsonReader reader, out Guid value)
+        {
+            return reader.TryGetGuid(out value);
+        }
+
+        public override void Write(Guid value, Utf8JsonWriter writer)
+        {
+            writer.WriteStringValue(value);
+        }
+
+        public override void Write(Span<byte> escapedPropertyName, Guid value, Utf8JsonWriter writer)
+        {
+            writer.WriteString(escapedPropertyName, value);
+        }
+    }
+}
index 769e5e2..8b53fce 100644 (file)
@@ -7,6 +7,7 @@ using System.Collections.Generic;
 using System.Diagnostics;
 using System.Reflection;
 using System.Runtime.InteropServices;
+using System.Text.Json.Serialization.Converters;
 
 namespace System.Text.Json.Serialization
 {
@@ -349,8 +350,7 @@ namespace System.Text.Json.Serialization
                 type = Nullable.GetUnderlyingType(type);
             }
 
-            // A Type is considered a value if it implements IConvertible or is a DateTimeOffset or JsonElement.
-            if (typeof(IConvertible).IsAssignableFrom(type) || type == typeof(DateTimeOffset) || type == typeof(JsonElement))
+            if (DefaultConverters.IsValueConvertable(type))
             {
                 return ClassType.Value;
             }
index c61e99f..83749c4 100644 (file)
@@ -25,6 +25,7 @@ namespace System.Text.Json.Serialization.Tests
         public double? MyDouble { get; set; }
         public DateTime? MyDateTime { get; set; }
         public DateTimeOffset? MyDateTimeOffset { get; set; }
+        public Guid? MyGuid { get; set; }
         public SampleEnum? MyEnum { get; set; }
         public short?[] MyInt16Array { get; set; }
         public int?[] MyInt32Array { get; set; }
@@ -42,6 +43,7 @@ namespace System.Text.Json.Serialization.Tests
         public double?[] MyDoubleArray { get; set; }
         public DateTime?[] MyDateTimeArray { get; set; }
         public DateTimeOffset?[] MyDateTimeOffsetArray { get; set; }
+        public Guid?[] MyGuidArray { get; set; }
         public SampleEnum?[] MyEnumArray { get; set; }
         public Dictionary<string, string> MyStringToStringDict { get; set; }
         public List<int?> MyListOfNullInt { get; set; }
@@ -71,6 +73,7 @@ namespace System.Text.Json.Serialization.Tests
             Assert.Null(MyDouble);
             Assert.Null(MyDateTime);
             Assert.Null(MyDateTimeOffset);
+            Assert.Null(MyGuid);
             Assert.Null(MyEnum);
 
             Assert.Null(MyInt16Array);
@@ -89,6 +92,7 @@ namespace System.Text.Json.Serialization.Tests
             Assert.Null(MyDoubleArray);
             Assert.Null(MyDateTimeArray);
             Assert.Null(MyDateTimeOffsetArray);
+            Assert.Null(MyGuidArray);
             Assert.Null(MyEnumArray);
             Assert.Null(MyStringToStringDict);
             Assert.Null(MyListOfNullInt);
@@ -111,6 +115,7 @@ namespace System.Text.Json.Serialization.Tests
                 @"""MyDecimal"" : null," +
                 @"""MyDateTime"" : null," +
                 @"""MyDateTimeOffset"" : null," +
+                @"""MyGuid"" : null," +
                 @"""MyEnum"" : null," +
                 @"""MyInt16Array"" : null," +
                 @"""MyInt32Array"" : null," +
@@ -156,6 +161,7 @@ namespace System.Text.Json.Serialization.Tests
                 @"""MyDecimal"" : 3.3," +
                 @"""MyDateTime"" : ""2019-01-30T12:01:02.0000000Z""," +
                 @"""MyDateTimeOffset"" : ""2019-01-30T12:01:02.0000000+01:00""," +
+                @"""MyGuid"" : ""1B33498A-7B7D-4DDA-9C13-F6AA4AB449A6""," +
                 @"""MyEnum"" : 2," +
                 @"""MyInt16Array"" : [1]," +
                 @"""MyInt32Array"" : [2]," +
@@ -173,6 +179,7 @@ namespace System.Text.Json.Serialization.Tests
                 @"""MyDecimalArray"" : [3.3]," +
                 @"""MyDateTimeArray"" : [""2019-01-30T12:01:02.0000000Z""]," +
                 @"""MyDateTimeOffsetArray"" : [""2019-01-30T12:01:02.0000000+01:00""]," +
+                @"""MyGuidArray"" : [""1B33498A-7B7D-4DDA-9C13-F6AA4AB449A6""]," +
                 @"""MyEnumArray"" : [2]," +
                 @"""MyStringToStringDict"" : {""key"" : ""value""}," +
                 @"""MyListOfNullInt"" : [null]" +
@@ -198,6 +205,7 @@ namespace System.Text.Json.Serialization.Tests
             MyDecimal = 3.3m;
             MyDateTime = new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc);
             MyDateTimeOffset = new DateTimeOffset(2019, 1, 30, 12, 1, 2, new TimeSpan(1, 0, 0));
+            MyGuid = new Guid("1B33498A-7B7D-4DDA-9C13-F6AA4AB449A6");
             MyEnum = SampleEnum.Two;
 
             MyInt16Array = new short?[] { 1 };
@@ -216,6 +224,7 @@ namespace System.Text.Json.Serialization.Tests
             MyDecimalArray = new decimal?[] { 3.3m };
             MyDateTimeArray = new DateTime?[] { new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc) };
             MyDateTimeOffsetArray = new DateTimeOffset?[] { new DateTimeOffset(2019, 1, 30, 12, 1, 2, new TimeSpan(1, 0, 0)) };
+            MyGuidArray = new Guid?[] { new Guid("1B33498A-7B7D-4DDA-9C13-F6AA4AB449A6") };
             MyEnumArray = new SampleEnum?[] { SampleEnum.Two };
             MyStringToStringDict = new Dictionary<string, string> { { "key", "value" } };
             MyListOfNullInt = new List<int?> { null };
@@ -239,6 +248,7 @@ namespace System.Text.Json.Serialization.Tests
             Assert.Equal(MyDouble, 2.2d);
             Assert.Equal(MyDateTime, new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc));
             Assert.Equal(MyDateTimeOffset, new DateTimeOffset(2019, 1, 30, 12, 1, 2, new TimeSpan(1, 0, 0)));
+            Assert.Equal(MyGuid, new Guid("1B33498A-7B7D-4DDA-9C13-F6AA4AB449A6"));
             Assert.Equal(MyEnum, SampleEnum.Two);
 
             Assert.Equal((short)1, MyInt16Array[0]);
@@ -257,6 +267,7 @@ namespace System.Text.Json.Serialization.Tests
             Assert.Equal(2.2d, MyDoubleArray[0]);
             Assert.Equal(new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc), MyDateTimeArray[0]);
             Assert.Equal(new DateTimeOffset(2019, 1, 30, 12, 1, 2, new TimeSpan(1, 0, 0)), MyDateTimeOffsetArray[0]);
+            Assert.Equal(new Guid("1B33498A-7B7D-4DDA-9C13-F6AA4AB449A6"), MyGuidArray[0]);
             Assert.Equal(SampleEnum.Two, MyEnumArray[0]);
             Assert.Equal("value", MyStringToStringDict["key"]);
             Assert.Null(MyListOfNullInt[0]);
index 103f646..6043dc2 100644 (file)
@@ -24,6 +24,7 @@ namespace System.Text.Json.Serialization.Tests
         public object[] MySingle { get; set; }
         public object[] MyDouble { get; set; }
         public object[] MyDateTime { get; set; }
+        public object[] MyGuid { get; set; }
         public object[] MyEnum { get; set; }
 
         public static readonly string s_json =
@@ -44,6 +45,7 @@ namespace System.Text.Json.Serialization.Tests
                 @"""MyDouble"" : [2.2]," +
                 @"""MyDecimal"" : [3.3]," +
                 @"""MyDateTime"" : [""2019-01-30T12:01:02.0000000Z""]," +
+                @"""MyGuid"" : [""97E9F02C-337E-4615-B26C-0020F5DC28C9""]," +
                 @"""MyEnum"" : [2]" + // int by default
             @"}";
 
@@ -71,6 +73,7 @@ namespace System.Text.Json.Serialization.Tests
             MyDouble = new object[] { 2.2d };
             MyDecimal = new object[] { 3.3m };
             MyDateTime = new object[] { new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc) };
+            MyGuid = new object[] { new Guid("97E9F02C-337E-4615-B26C-0020F5DC28C9") };
             MyEnum = new object[] { SampleEnum.Two };
         }
 
@@ -131,6 +134,9 @@ namespace System.Text.Json.Serialization.Tests
             Assert.IsType<JsonElement>(MyDateTime[0]);
             Assert.Equal(JsonValueType.String, ((JsonElement)MyDateTime[0]).Type);
             Assert.Equal(new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc), ((JsonElement)MyDateTime[0]).GetDateTime());
+            Assert.IsType<JsonElement>(MyGuid[0]);
+            Assert.Equal(JsonValueType.String, ((JsonElement)MyGuid[0]).Type);
+            Assert.Equal(new Guid("97E9F02C-337E-4615-B26C-0020F5DC28C9"), ((JsonElement)MyGuid[0]).GetGuid());
             Assert.IsType<JsonElement>(MyEnum[0]);
             Assert.Equal(JsonValueType.Number, ((JsonElement)MyEnum[0]).Type);
             Assert.Equal(SampleEnum.Two, (SampleEnum)((JsonElement)MyEnum[0]).GetUInt32());
index 55ce2fd..5060fac 100644 (file)
@@ -24,6 +24,7 @@ namespace System.Text.Json.Serialization.Tests
         public object MySingle { get; set; }
         public object MyDouble { get; set; }
         public object MyDateTime { get; set; }
+        public object MyGuid { get; set; }
         public object MyEnum { get; set; }
 
         public static readonly string s_json =
@@ -44,6 +45,7 @@ namespace System.Text.Json.Serialization.Tests
                 @"""MyDouble"" : 2.2," +
                 @"""MyDecimal"" : 3.3," +
                 @"""MyDateTime"" : ""2019-01-30T12:01:02.0000000Z""," +
+                @"""MyGuid"" : ""5BB9D872-DA8A-471E-AA70-08E19102683D""," +
                 @"""MyEnum"" : 2" + // int by default
             @"}";
 
@@ -70,6 +72,7 @@ namespace System.Text.Json.Serialization.Tests
             MyDouble = 2.2d;
             MyDecimal = 3.3m;
             MyDateTime = new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc);
+            MyGuid = new Guid("5BB9D872-DA8A-471E-AA70-08E19102683D");
             MyEnum = SampleEnum.Two;
         }
 
@@ -130,6 +133,9 @@ namespace System.Text.Json.Serialization.Tests
             Assert.IsType<JsonElement>(MyDateTime);
             Assert.Equal(JsonValueType.String, ((JsonElement)MyDateTime).Type);
             Assert.Equal(new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc), ((JsonElement)MyDateTime).GetDateTime());
+            Assert.IsType<JsonElement>(MyGuid);
+            Assert.Equal(JsonValueType.String, ((JsonElement)MyGuid).Type);
+            Assert.Equal(new Guid("5BB9D872-DA8A-471E-AA70-08E19102683D"), ((JsonElement)MyGuid).GetGuid());
             Assert.IsType<JsonElement>(MyEnum);
             Assert.Equal(JsonValueType.Number, ((JsonElement)MyEnum).Type);
             Assert.Equal(SampleEnum.Two, (SampleEnum)((JsonElement)MyEnum).GetUInt32());