From 6844583dc7aa69e76d7012eacfd6fcc50a3b0ec9 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Mon, 11 May 2020 13:14:41 -0700 Subject: [PATCH 01/12] add stack of T converter --- .../system-text-json-converters-how-to.md | 13 ++++ .../csharp/JsonConverterFactoryForStackOfT.cs | 74 +++++++++++++++++++ .../core/system-text-json/csharp/Program.cs | 3 + .../csharp/RoundtripStackOfT.cs | 29 ++++++++ 4 files changed, 119 insertions(+) create mode 100644 samples/snippets/core/system-text-json/csharp/JsonConverterFactoryForStackOfT.cs create mode 100644 samples/snippets/core/system-text-json/csharp/RoundtripStackOfT.cs diff --git a/docs/standard/serialization/system-text-json-converters-how-to.md b/docs/standard/serialization/system-text-json-converters-how-to.md index 37d42e15b80f9..ba731234c818c 100644 --- a/docs/standard/serialization/system-text-json-converters-how-to.md +++ b/docs/standard/serialization/system-text-json-converters-how-to.md @@ -24,6 +24,7 @@ You can also write custom converters to customize or extend `System.Text.Json` w * [Deserialize inferred types to object properties](#deserialize-inferred-types-to-object-properties). * [Support Dictionary with non-string key](#support-dictionary-with-non-string-key). * [Support polymorphic deserialization](#support-polymorphic-deserialization). +* [Support round-trip for Stack\](#support-round-trip-for-stackt) ## Custom converter patterns @@ -279,6 +280,18 @@ The converter can deserialize JSON that was created by using the same converter The converter code in the preceding example reads and writes each property manually. An alternative is to call `Deserialize` or `Serialize` to do some of the work. For an example, see [this StackOverflow post](https://stackoverflow.com/a/59744873/12509023). +### Support round-trip for Stack\ + +If you deserialize a JSON string into a object and then serialize that object, the contents of the stack are in reverse order. To support serialization and deserialization that retains the original order in the stack, a custom converter is required. + +The following code shows a custom converter that enables round trips to and from `Stack` objects: + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/JsonConverterFactoryForStackOfT.cs)] + +The following code registers the converter: + +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/RoundtripDictionaryTkeyEnumTValue.cs?name=SnippetRegister)] + ## Other custom converter samples The [Migrate from Newtonsoft.Json to System.Text.Json](system-text-json-migrate-from-newtonsoft-how-to.md) article contains additional samples of custom converters. diff --git a/samples/snippets/core/system-text-json/csharp/JsonConverterFactoryForStackOfT.cs b/samples/snippets/core/system-text-json/csharp/JsonConverterFactoryForStackOfT.cs new file mode 100644 index 0000000000000..303c317bdfbfd --- /dev/null +++ b/samples/snippets/core/system-text-json/csharp/JsonConverterFactoryForStackOfT.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Reflection; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace SystemTextJsonSamples +{ + public class JsonConverterFactoryForStackOfT : JsonConverterFactory + { + public override bool CanConvert(Type typeToConvert) + { + return typeToConvert.IsGenericType && typeToConvert.GetGenericTypeDefinition() == typeof(Stack<>); + } + + public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) + { + Debug.Assert(typeToConvert.IsGenericType && typeToConvert.GetGenericTypeDefinition() == typeof(Stack<>)); + + Type elementType = typeToConvert.GetGenericArguments()[0]; + + JsonConverter converter = (JsonConverter)Activator.CreateInstance( + typeof(JsonConverterForStackOfT<>).MakeGenericType(new Type[] { elementType }), + BindingFlags.Instance | BindingFlags.Public, + binder: null, + args: null, + culture: null)!; + + return converter; + } + } + + public class JsonConverterForStackOfT : JsonConverter> + { + public override Stack Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType != JsonTokenType.StartArray || !reader.Read()) + { + throw new JsonException(); + } + + var elements = new Stack(); + + while (reader.TokenType != JsonTokenType.EndArray) + { + elements.Push(JsonSerializer.Deserialize(ref reader, options)); + + if (!reader.Read()) + { + throw new JsonException(); + } + } + + return elements; + } + + public override void Write(Utf8JsonWriter writer, Stack value, JsonSerializerOptions options) + { + writer.WriteStartArray(); + + var reversed = new Stack(value); + + foreach (T item in reversed) + { + JsonSerializer.Serialize(writer, item, options); + } + + writer.WriteEndArray(); + } + } +} diff --git a/samples/snippets/core/system-text-json/csharp/Program.cs b/samples/snippets/core/system-text-json/csharp/Program.cs index 557a78015bce5..a4bf0e9d7ebd1 100644 --- a/samples/snippets/core/system-text-json/csharp/Program.cs +++ b/samples/snippets/core/system-text-json/csharp/Program.cs @@ -36,6 +36,9 @@ static async Task Main(string[] args) Console.WriteLine("\n============================= Roundtrip enum as string\n"); RoundtripEnumAsString.Run(); + Console.WriteLine("\n============================= Roundtrip Stack\n"); + RoundtripStackOfT.Run(); + Console.WriteLine("\n============================= Serialize polymorphic\n"); SerializePolymorphic.Run(); diff --git a/samples/snippets/core/system-text-json/csharp/RoundtripStackOfT.cs b/samples/snippets/core/system-text-json/csharp/RoundtripStackOfT.cs new file mode 100644 index 0000000000000..10e5e7b0e1cd4 --- /dev/null +++ b/samples/snippets/core/system-text-json/csharp/RoundtripStackOfT.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Text.Json; + +namespace SystemTextJsonSamples +{ + public class RoundtripStackOfT + { + public static void Run() + { + Console.WriteLine("Deserialize JSON string [1, 2, 3], then deserialize"); + Stack stack = JsonSerializer.Deserialize>("[1, 2, 3]"); + string serialized = JsonSerializer.Serialize(stack); + Console.WriteLine($"Result is reverse order {serialized}"); + + Console.WriteLine("Deserialize JSON string [1, 2, 3] with custom converter, then deserialize"); + var options = new JsonSerializerOptions + { + Converters = { new JsonConverterFactoryForStackOfT() }, + }; + stack = JsonSerializer.Deserialize>("[1, 2, 3]", options); + serialized = JsonSerializer.Serialize(stack, options); + Console.WriteLine($"Result is same order {serialized}"); + } + } +} + From db26d8ee544bb81054fc394c8197d987920f84c9 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Mon, 11 May 2020 13:19:41 -0700 Subject: [PATCH 02/12] fix snippet link --- .../serialization/system-text-json-converters-how-to.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/standard/serialization/system-text-json-converters-how-to.md b/docs/standard/serialization/system-text-json-converters-how-to.md index ba731234c818c..4a59d0a779149 100644 --- a/docs/standard/serialization/system-text-json-converters-how-to.md +++ b/docs/standard/serialization/system-text-json-converters-how-to.md @@ -290,7 +290,7 @@ The following code shows a custom converter that enables round trips to and from The following code registers the converter: -[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/RoundtripDictionaryTkeyEnumTValue.cs?name=SnippetRegister)] +[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/RoundtripStackOfT.cs?name=SnippetRegister)] ## Other custom converter samples From 4504e66c40cba13b3f19ca5ef3578db9106e897f Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Mon, 11 May 2020 13:24:12 -0700 Subject: [PATCH 03/12] clean up usings --- .../system-text-json/csharp/JsonConverterFactoryForStackOfT.cs | 2 -- .../snippets/core/system-text-json/csharp/RoundtripStackOfT.cs | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/snippets/core/system-text-json/csharp/JsonConverterFactoryForStackOfT.cs b/samples/snippets/core/system-text-json/csharp/JsonConverterFactoryForStackOfT.cs index 303c317bdfbfd..7fc2b4647c689 100644 --- a/samples/snippets/core/system-text-json/csharp/JsonConverterFactoryForStackOfT.cs +++ b/samples/snippets/core/system-text-json/csharp/JsonConverterFactoryForStackOfT.cs @@ -1,7 +1,5 @@ using System; -using System.Collections; using System.Collections.Generic; -using System.Collections.Immutable; using System.Diagnostics; using System.Reflection; using System.Text.Json; diff --git a/samples/snippets/core/system-text-json/csharp/RoundtripStackOfT.cs b/samples/snippets/core/system-text-json/csharp/RoundtripStackOfT.cs index 10e5e7b0e1cd4..32fc0001f3501 100644 --- a/samples/snippets/core/system-text-json/csharp/RoundtripStackOfT.cs +++ b/samples/snippets/core/system-text-json/csharp/RoundtripStackOfT.cs @@ -16,10 +16,12 @@ public static void Run() Console.WriteLine($"Result is reverse order {serialized}"); Console.WriteLine("Deserialize JSON string [1, 2, 3] with custom converter, then deserialize"); + // var options = new JsonSerializerOptions { Converters = { new JsonConverterFactoryForStackOfT() }, }; + // stack = JsonSerializer.Deserialize>("[1, 2, 3]", options); serialized = JsonSerializer.Serialize(stack, options); Console.WriteLine($"Result is same order {serialized}"); From 61ddb350150cc973f44038ba29a30d0fe41f0b8d Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Mon, 11 May 2020 13:30:49 -0700 Subject: [PATCH 04/12] shorten code lines --- .../csharp/JsonConverterFactoryForStackOfT.cs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/samples/snippets/core/system-text-json/csharp/JsonConverterFactoryForStackOfT.cs b/samples/snippets/core/system-text-json/csharp/JsonConverterFactoryForStackOfT.cs index 7fc2b4647c689..3811fe60ee070 100644 --- a/samples/snippets/core/system-text-json/csharp/JsonConverterFactoryForStackOfT.cs +++ b/samples/snippets/core/system-text-json/csharp/JsonConverterFactoryForStackOfT.cs @@ -11,17 +11,21 @@ public class JsonConverterFactoryForStackOfT : JsonConverterFactory { public override bool CanConvert(Type typeToConvert) { - return typeToConvert.IsGenericType && typeToConvert.GetGenericTypeDefinition() == typeof(Stack<>); + return typeToConvert.IsGenericType && + typeToConvert.GetGenericTypeDefinition() == typeof(Stack<>); } - public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) + public override JsonConverter CreateConverter( + Type typeToConvert, JsonSerializerOptions options) { - Debug.Assert(typeToConvert.IsGenericType && typeToConvert.GetGenericTypeDefinition() == typeof(Stack<>)); + Debug.Assert(typeToConvert.IsGenericType && + typeToConvert.GetGenericTypeDefinition() == typeof(Stack<>)); Type elementType = typeToConvert.GetGenericArguments()[0]; JsonConverter converter = (JsonConverter)Activator.CreateInstance( - typeof(JsonConverterForStackOfT<>).MakeGenericType(new Type[] { elementType }), + typeof(JsonConverterForStackOfT<>) + .MakeGenericType(new Type[] { elementType }), BindingFlags.Instance | BindingFlags.Public, binder: null, args: null, @@ -33,7 +37,8 @@ public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializer public class JsonConverterForStackOfT : JsonConverter> { - public override Stack Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override Stack Read( + ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType != JsonTokenType.StartArray || !reader.Read()) { @@ -55,7 +60,8 @@ public override Stack Read(ref Utf8JsonReader reader, Type typeToConvert, Jso return elements; } - public override void Write(Utf8JsonWriter writer, Stack value, JsonSerializerOptions options) + public override void Write( + Utf8JsonWriter writer, Stack value, JsonSerializerOptions options) { writer.WriteStartArray(); From 87d71d18dd90a2c9fbbc9e81a02726cbc18766ce Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Mon, 11 May 2020 13:35:43 -0700 Subject: [PATCH 05/12] add missing link to h3 --- .../serialization/system-text-json-converters-how-to.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/standard/serialization/system-text-json-converters-how-to.md b/docs/standard/serialization/system-text-json-converters-how-to.md index 4a59d0a779149..7bce92651b241 100644 --- a/docs/standard/serialization/system-text-json-converters-how-to.md +++ b/docs/standard/serialization/system-text-json-converters-how-to.md @@ -24,7 +24,7 @@ You can also write custom converters to customize or extend `System.Text.Json` w * [Deserialize inferred types to object properties](#deserialize-inferred-types-to-object-properties). * [Support Dictionary with non-string key](#support-dictionary-with-non-string-key). * [Support polymorphic deserialization](#support-polymorphic-deserialization). -* [Support round-trip for Stack\](#support-round-trip-for-stackt) +* [Support round-trip for Stack\](#support-round-trip-for-stackt). ## Custom converter patterns @@ -173,6 +173,7 @@ The following sections provide converter samples that address some common scenar * [Deserialize inferred types to object properties](#deserialize-inferred-types-to-object-properties) * [Support Dictionary with non-string key](#support-dictionary-with-non-string-key) * [Support polymorphic deserialization](#support-polymorphic-deserialization) +* [Support round-trip for Stack\](#support-round-trip-for-stackt). ### Deserialize inferred types to object properties From 8bd0e01e400b7e05d34d614f888595eeae73a9f3 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Wed, 13 May 2020 16:03:34 -0700 Subject: [PATCH 06/12] Update docs/standard/serialization/system-text-json-converters-how-to.md Co-authored-by: Ahson Khan --- .../serialization/system-text-json-converters-how-to.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/standard/serialization/system-text-json-converters-how-to.md b/docs/standard/serialization/system-text-json-converters-how-to.md index 7bce92651b241..d88869ce1b4dd 100644 --- a/docs/standard/serialization/system-text-json-converters-how-to.md +++ b/docs/standard/serialization/system-text-json-converters-how-to.md @@ -285,7 +285,7 @@ The converter code in the preceding example reads and writes each property manua If you deserialize a JSON string into a object and then serialize that object, the contents of the stack are in reverse order. To support serialization and deserialization that retains the original order in the stack, a custom converter is required. -The following code shows a custom converter that enables round trips to and from `Stack` objects: +The following code shows a custom converter that enables round-tripping to and from `Stack` objects: [!code-csharp[](~/samples/snippets/core/system-text-json/csharp/JsonConverterFactoryForStackOfT.cs)] From 3a771e735f8e7bd9dc69cbbccc3fbf9664f7db93 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Wed, 13 May 2020 16:03:51 -0700 Subject: [PATCH 07/12] Update samples/snippets/core/system-text-json/csharp/RoundtripStackOfT.cs Co-authored-by: Ahson Khan --- .../snippets/core/system-text-json/csharp/RoundtripStackOfT.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/samples/snippets/core/system-text-json/csharp/RoundtripStackOfT.cs b/samples/snippets/core/system-text-json/csharp/RoundtripStackOfT.cs index 32fc0001f3501..b5e3fce1cb27b 100644 --- a/samples/snippets/core/system-text-json/csharp/RoundtripStackOfT.cs +++ b/samples/snippets/core/system-text-json/csharp/RoundtripStackOfT.cs @@ -10,7 +10,7 @@ public class RoundtripStackOfT { public static void Run() { - Console.WriteLine("Deserialize JSON string [1, 2, 3], then deserialize"); + Console.WriteLine("Deserialize JSON string [1, 2, 3], then serialize it back to JSON."); Stack stack = JsonSerializer.Deserialize>("[1, 2, 3]"); string serialized = JsonSerializer.Serialize(stack); Console.WriteLine($"Result is reverse order {serialized}"); @@ -28,4 +28,3 @@ public static void Run() } } } - From 0ffe435d2312e75ba27891dcf5220df38f635bc2 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Wed, 13 May 2020 16:04:26 -0700 Subject: [PATCH 08/12] Update samples/snippets/core/system-text-json/csharp/RoundtripStackOfT.cs Co-authored-by: Ahson Khan --- .../snippets/core/system-text-json/csharp/RoundtripStackOfT.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/snippets/core/system-text-json/csharp/RoundtripStackOfT.cs b/samples/snippets/core/system-text-json/csharp/RoundtripStackOfT.cs index b5e3fce1cb27b..a40b293cbf6fa 100644 --- a/samples/snippets/core/system-text-json/csharp/RoundtripStackOfT.cs +++ b/samples/snippets/core/system-text-json/csharp/RoundtripStackOfT.cs @@ -13,7 +13,7 @@ public static void Run() Console.WriteLine("Deserialize JSON string [1, 2, 3], then serialize it back to JSON."); Stack stack = JsonSerializer.Deserialize>("[1, 2, 3]"); string serialized = JsonSerializer.Serialize(stack); - Console.WriteLine($"Result is reverse order {serialized}"); + Console.WriteLine($"Result is in reverse order: {serialized}"); Console.WriteLine("Deserialize JSON string [1, 2, 3] with custom converter, then deserialize"); // From c98cf2984bb4eb303e7124b8d348e821a8ded36b Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Wed, 13 May 2020 16:04:41 -0700 Subject: [PATCH 09/12] Update samples/snippets/core/system-text-json/csharp/RoundtripStackOfT.cs Co-authored-by: Ahson Khan --- .../snippets/core/system-text-json/csharp/RoundtripStackOfT.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/snippets/core/system-text-json/csharp/RoundtripStackOfT.cs b/samples/snippets/core/system-text-json/csharp/RoundtripStackOfT.cs index a40b293cbf6fa..38fa8df2dfaa2 100644 --- a/samples/snippets/core/system-text-json/csharp/RoundtripStackOfT.cs +++ b/samples/snippets/core/system-text-json/csharp/RoundtripStackOfT.cs @@ -15,7 +15,7 @@ public static void Run() string serialized = JsonSerializer.Serialize(stack); Console.WriteLine($"Result is in reverse order: {serialized}"); - Console.WriteLine("Deserialize JSON string [1, 2, 3] with custom converter, then deserialize"); + Console.WriteLine("Deserialize JSON string [1, 2, 3] with custom converter, then serialize it back to JSON."); // var options = new JsonSerializerOptions { From e589dd88a977bfa661f83cf4ac3cfecd4cb32f35 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Wed, 13 May 2020 16:04:57 -0700 Subject: [PATCH 10/12] Update samples/snippets/core/system-text-json/csharp/RoundtripStackOfT.cs Co-authored-by: Ahson Khan --- .../snippets/core/system-text-json/csharp/RoundtripStackOfT.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/snippets/core/system-text-json/csharp/RoundtripStackOfT.cs b/samples/snippets/core/system-text-json/csharp/RoundtripStackOfT.cs index 38fa8df2dfaa2..123085d0a2a55 100644 --- a/samples/snippets/core/system-text-json/csharp/RoundtripStackOfT.cs +++ b/samples/snippets/core/system-text-json/csharp/RoundtripStackOfT.cs @@ -24,7 +24,7 @@ public static void Run() // stack = JsonSerializer.Deserialize>("[1, 2, 3]", options); serialized = JsonSerializer.Serialize(stack, options); - Console.WriteLine($"Result is same order {serialized}"); + Console.WriteLine($"Result is in same order: {serialized}"); } } } From 603eecf9370f19d1ff48cc44ce30e9fd3f5f3204 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Wed, 13 May 2020 16:08:57 -0700 Subject: [PATCH 11/12] address feedback --- .../serialization/system-text-json-converters-how-to.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/standard/serialization/system-text-json-converters-how-to.md b/docs/standard/serialization/system-text-json-converters-how-to.md index 7bce92651b241..73171dd42dd2f 100644 --- a/docs/standard/serialization/system-text-json-converters-how-to.md +++ b/docs/standard/serialization/system-text-json-converters-how-to.md @@ -283,7 +283,14 @@ The converter code in the preceding example reads and writes each property manua ### Support round-trip for Stack\ -If you deserialize a JSON string into a object and then serialize that object, the contents of the stack are in reverse order. To support serialization and deserialization that retains the original order in the stack, a custom converter is required. +If you deserialize a JSON string into a object and then serialize that object, the contents of the stack are in reverse order. This behavior applies to the following types and interface, and user-defined types that derive from them: + +* +* +* +* + +To support serialization and deserialization that retains the original order in the stack, a custom converter is required. The following code shows a custom converter that enables round trips to and from `Stack` objects: From 6cf86e73be961226d5034dff0298b1e85d9a7cba Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Thu, 14 May 2020 09:02:23 -0700 Subject: [PATCH 12/12] add concurrentstack --- .../standard/serialization/system-text-json-converters-how-to.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/standard/serialization/system-text-json-converters-how-to.md b/docs/standard/serialization/system-text-json-converters-how-to.md index ac702d376906c..4b2abdbbb17be 100644 --- a/docs/standard/serialization/system-text-json-converters-how-to.md +++ b/docs/standard/serialization/system-text-json-converters-how-to.md @@ -287,6 +287,7 @@ If you deserialize a JSON string into a * +* * *