From d868a51542715f1051bc0797443eb13b7e117ae6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Jul 2026 08:16:21 +0000 Subject: [PATCH 1/8] Initial plan From c2ca7994f566ba6344f503a11c7ac216f2a121d9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Jul 2026 08:23:01 +0000 Subject: [PATCH 2/8] Percent-encode JSON pointer tokens in JsonSchemaExporter $ref values Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com> --- .../Text/Json/Schema/JsonSchemaExporter.cs | 138 +++++++++++++++--- .../JsonSchemaExporterTests.TestTypes.cs | 6 +- 2 files changed, 119 insertions(+), 25 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs index 1ac5814543c963..eec1f2b1c728ef 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs @@ -553,37 +553,131 @@ private static string FormatJsonPointer(ReadOnlySpan path) foreach (string segment in path) { - ReadOnlySpan span = segment.AsSpan(); sb.Append('/'); + AppendEscapedReferenceToken(ref sb, segment); + } - do - { - // Per RFC 6901 the characters '~' and '/' must be escaped. - int pos = span.IndexOfAny('~', '/'); - if (pos < 0) - { - sb.Append(span); - break; - } - - sb.Append(span.Slice(0, pos)); + return sb.ToString(); + } - if (span[pos] == '~') - { + private static void AppendEscapedReferenceToken(ref ValueStringBuilder sb, string segment) + { + for (int i = 0; i < segment.Length; i++) + { + char c = segment[i]; + switch (c) + { + // Per RFC 6901 the characters '~' and '/' are escaped as '~0' and '~1'. + case '~': sb.Append("~0"); - } - else - { - Debug.Assert(span[pos] == '/'); + break; + case '/': sb.Append("~1"); - } + break; + default: + if (IsUnescapedFragmentChar(c)) + { + sb.Append(c); + } + else + { + // Per RFC 6901 section 6 the JSON Pointer is embedded in a URI fragment, + // so any characters outside the RFC 3986 'fragment' production are + // percent-encoded using their UTF-8 octets. + int codePoint = c; + if (char.IsHighSurrogate(c) && i + 1 < segment.Length && char.IsLowSurrogate(segment[i + 1])) + { + codePoint = char.ConvertToUtf32(c, segment[i + 1]); + i++; + } - span = span.Slice(pos + 1); + AppendPercentEncoded(ref sb, codePoint); + } + + break; } - while (!span.IsEmpty); } + } - return sb.ToString(); + private static void AppendPercentEncoded(ref ValueStringBuilder sb, int codePoint) + { + Span utf8Bytes = stackalloc byte[4]; + int byteCount; + + if (codePoint <= 0x7F) + { + utf8Bytes[0] = (byte)codePoint; + byteCount = 1; + } + else if (codePoint <= 0x7FF) + { + utf8Bytes[0] = (byte)(0xC0 | (codePoint >> 6)); + utf8Bytes[1] = (byte)(0x80 | (codePoint & 0x3F)); + byteCount = 2; + } + else if (codePoint <= 0xFFFF) + { + utf8Bytes[0] = (byte)(0xE0 | (codePoint >> 12)); + utf8Bytes[1] = (byte)(0x80 | ((codePoint >> 6) & 0x3F)); + utf8Bytes[2] = (byte)(0x80 | (codePoint & 0x3F)); + byteCount = 3; + } + else + { + utf8Bytes[0] = (byte)(0xF0 | (codePoint >> 18)); + utf8Bytes[1] = (byte)(0x80 | ((codePoint >> 12) & 0x3F)); + utf8Bytes[2] = (byte)(0x80 | ((codePoint >> 6) & 0x3F)); + utf8Bytes[3] = (byte)(0x80 | (codePoint & 0x3F)); + byteCount = 4; + } + + const string HexDigits = "0123456789ABCDEF"; + for (int i = 0; i < byteCount; i++) + { + byte b = utf8Bytes[i]; + sb.Append('%'); + sb.Append(HexDigits[b >> 4]); + sb.Append(HexDigits[b & 0xF]); + } + } + + private static bool IsUnescapedFragmentChar(char c) + { + // Characters permitted unescaped by the RFC 3986 'fragment' production: + // fragment = *( pchar / "/" / "?" ) + // pchar = unreserved / sub-delims / ":" / "@" + // unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + // sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "=" + // '/' is handled separately as the '~1' escape, so it is intentionally excluded here. + if ((uint)(c - 'A') <= 'Z' - 'A' || (uint)(c - 'a') <= 'z' - 'a' || (uint)(c - '0') <= '9' - '0') + { + return true; + } + + switch (c) + { + case '-': + case '.': + case '_': + case '~': + case '!': + case '$': + case '&': + case '\'': + case '(': + case ')': + case '*': + case '+': + case ',': + case ';': + case '=': + case ':': + case '@': + case '?': + return true; + default: + return false; + } } } } diff --git a/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs b/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs index 065f18e501d5ec..1214cf940bd320 100644 --- a/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs +++ b/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs @@ -1152,7 +1152,7 @@ of the type which points to the first occurrence. */ { "type": ["object","null"], "properties": { - "~/path/to/value": { + "~/path/to/value%20^": { "type": "object", "properties": { "Value" : {"type":"integer"}, @@ -1160,7 +1160,7 @@ of the type which points to the first occurrence. */ "type": ["object","null"], "properties": { "Value" : {"type":"integer"}, - "Next": {"$ref":"#/properties/~0~1path~1to~1value/properties/Next"} + "Next": {"$ref":"#/properties/~0~1path~1to~1value%2520%5E/properties/Next"} } } } @@ -1610,7 +1610,7 @@ public ClassWithComponentModelAttributes(string stringValue, [DefaultValue(42)] public class ClassWithJsonPointerEscapablePropertyNames { - [JsonPropertyName("~/path/to/value")] + [JsonPropertyName("~/path/to/value%20^")] public PocoWithRecursiveMembers Value { get; set; } } From 016a791570cceb2131e018de4fcd408aba9e4029 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Jul 2026 08:51:23 +0000 Subject: [PATCH 3/8] Fix ValueStringBuilder ref usage; validated schema exporter tests pass Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com> --- .../Text/Json/Schema/JsonSchemaExporter.cs | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs index eec1f2b1c728ef..3f9840b0548e1f 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs @@ -548,16 +548,23 @@ private static string FormatJsonPointer(ReadOnlySpan path) return "#"; } - using ValueStringBuilder sb = new(initialCapacity: path.Length * 10); - sb.Append('#'); + ValueStringBuilder sb = new(initialCapacity: path.Length * 10); + try + { + sb.Append('#'); + + foreach (string segment in path) + { + sb.Append('/'); + AppendEscapedReferenceToken(ref sb, segment); + } - foreach (string segment in path) + return sb.ToString(); + } + finally { - sb.Append('/'); - AppendEscapedReferenceToken(ref sb, segment); + sb.Dispose(); } - - return sb.ToString(); } private static void AppendEscapedReferenceToken(ref ValueStringBuilder sb, string segment) From c4c2952c545a1834481e345b2dc5d1e47ad7e879 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Jul 2026 08:53:07 +0000 Subject: [PATCH 4/8] Address review: idiomatic surrogate-pair check and clarifying comment Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com> --- .../src/System/Text/Json/Schema/JsonSchemaExporter.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs index 3f9840b0548e1f..5a3ae2287b2224 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs @@ -549,6 +549,7 @@ private static string FormatJsonPointer(ReadOnlySpan path) } ValueStringBuilder sb = new(initialCapacity: path.Length * 10); + // Not using a 'using' declaration because 'sb' is passed by ref to helper methods. try { sb.Append('#'); @@ -592,7 +593,7 @@ private static void AppendEscapedReferenceToken(ref ValueStringBuilder sb, strin // so any characters outside the RFC 3986 'fragment' production are // percent-encoded using their UTF-8 octets. int codePoint = c; - if (char.IsHighSurrogate(c) && i + 1 < segment.Length && char.IsLowSurrogate(segment[i + 1])) + if (char.IsHighSurrogate(c) && i + 1 < segment.Length && char.IsSurrogatePair(c, segment[i + 1])) { codePoint = char.ConvertToUtf32(c, segment[i + 1]); i++; From a9eb5e019f89d29901ea0514ed84474b3a98a917 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Jul 2026 09:57:01 +0000 Subject: [PATCH 5/8] Use Uri.EscapeDataString for JSON pointer percent-encoding; simplify test property name Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com> --- .../Text/Json/Schema/JsonSchemaExporter.cs | 143 ++---------------- .../JsonSchemaExporterTests.TestTypes.cs | 6 +- 2 files changed, 14 insertions(+), 135 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs index 5a3ae2287b2224..f95312d886741e 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; @@ -548,144 +549,22 @@ private static string FormatJsonPointer(ReadOnlySpan path) return "#"; } - ValueStringBuilder sb = new(initialCapacity: path.Length * 10); - // Not using a 'using' declaration because 'sb' is passed by ref to helper methods. - try - { - sb.Append('#'); - - foreach (string segment in path) - { - sb.Append('/'); - AppendEscapedReferenceToken(ref sb, segment); - } - - return sb.ToString(); - } - finally - { - sb.Dispose(); - } - } - - private static void AppendEscapedReferenceToken(ref ValueStringBuilder sb, string segment) - { - for (int i = 0; i < segment.Length; i++) - { - char c = segment[i]; - switch (c) - { - // Per RFC 6901 the characters '~' and '/' are escaped as '~0' and '~1'. - case '~': - sb.Append("~0"); - break; - case '/': - sb.Append("~1"); - break; - default: - if (IsUnescapedFragmentChar(c)) - { - sb.Append(c); - } - else - { - // Per RFC 6901 section 6 the JSON Pointer is embedded in a URI fragment, - // so any characters outside the RFC 3986 'fragment' production are - // percent-encoded using their UTF-8 octets. - int codePoint = c; - if (char.IsHighSurrogate(c) && i + 1 < segment.Length && char.IsSurrogatePair(c, segment[i + 1])) - { - codePoint = char.ConvertToUtf32(c, segment[i + 1]); - i++; - } - - AppendPercentEncoded(ref sb, codePoint); - } + using ValueStringBuilder sb = new(initialCapacity: path.Length * 10); + sb.Append('#'); - break; - } - } - } - - private static void AppendPercentEncoded(ref ValueStringBuilder sb, int codePoint) - { - Span utf8Bytes = stackalloc byte[4]; - int byteCount; - - if (codePoint <= 0x7F) - { - utf8Bytes[0] = (byte)codePoint; - byteCount = 1; - } - else if (codePoint <= 0x7FF) - { - utf8Bytes[0] = (byte)(0xC0 | (codePoint >> 6)); - utf8Bytes[1] = (byte)(0x80 | (codePoint & 0x3F)); - byteCount = 2; - } - else if (codePoint <= 0xFFFF) + foreach (string segment in path) { - utf8Bytes[0] = (byte)(0xE0 | (codePoint >> 12)); - utf8Bytes[1] = (byte)(0x80 | ((codePoint >> 6) & 0x3F)); - utf8Bytes[2] = (byte)(0x80 | (codePoint & 0x3F)); - byteCount = 3; - } - else - { - utf8Bytes[0] = (byte)(0xF0 | (codePoint >> 18)); - utf8Bytes[1] = (byte)(0x80 | ((codePoint >> 12) & 0x3F)); - utf8Bytes[2] = (byte)(0x80 | ((codePoint >> 6) & 0x3F)); - utf8Bytes[3] = (byte)(0x80 | (codePoint & 0x3F)); - byteCount = 4; - } + sb.Append('/'); - const string HexDigits = "0123456789ABCDEF"; - for (int i = 0; i < byteCount; i++) - { - byte b = utf8Bytes[i]; - sb.Append('%'); - sb.Append(HexDigits[b >> 4]); - sb.Append(HexDigits[b & 0xF]); - } - } + // Per RFC 6901 the characters '~' and '/' are escaped as '~0' and '~1'. + string escapedToken = segment.Replace("~", "~0").Replace("/", "~1"); - private static bool IsUnescapedFragmentChar(char c) - { - // Characters permitted unescaped by the RFC 3986 'fragment' production: - // fragment = *( pchar / "/" / "?" ) - // pchar = unreserved / sub-delims / ":" / "@" - // unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" - // sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "=" - // '/' is handled separately as the '~1' escape, so it is intentionally excluded here. - if ((uint)(c - 'A') <= 'Z' - 'A' || (uint)(c - 'a') <= 'z' - 'a' || (uint)(c - '0') <= '9' - '0') - { - return true; + // Per RFC 6901 section 6 the JSON Pointer is embedded in a URI fragment, + // so percent-encode any characters that are not valid in a URI fragment. + sb.Append(Uri.EscapeDataString(escapedToken)); } - switch (c) - { - case '-': - case '.': - case '_': - case '~': - case '!': - case '$': - case '&': - case '\'': - case '(': - case ')': - case '*': - case '+': - case ',': - case ';': - case '=': - case ':': - case '@': - case '?': - return true; - default: - return false; - } + return sb.ToString(); } } } diff --git a/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs b/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs index 1214cf940bd320..332902b178736a 100644 --- a/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs +++ b/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs @@ -1152,7 +1152,7 @@ of the type which points to the first occurrence. */ { "type": ["object","null"], "properties": { - "~/path/to/value%20^": { + "~/path/to/value ^": { "type": "object", "properties": { "Value" : {"type":"integer"}, @@ -1160,7 +1160,7 @@ of the type which points to the first occurrence. */ "type": ["object","null"], "properties": { "Value" : {"type":"integer"}, - "Next": {"$ref":"#/properties/~0~1path~1to~1value%2520%5E/properties/Next"} + "Next": {"$ref":"#/properties/~0~1path~1to~1value%20%5E/properties/Next"} } } } @@ -1610,7 +1610,7 @@ public ClassWithComponentModelAttributes(string stringValue, [DefaultValue(42)] public class ClassWithJsonPointerEscapablePropertyNames { - [JsonPropertyName("~/path/to/value%20^")] + [JsonPropertyName("~/path/to/value ^")] public PocoWithRecursiveMembers Value { get; set; } } From dbc21553e30d8eb26c216f950bacd6edcdcafc23 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Jul 2026 10:00:02 +0000 Subject: [PATCH 6/8] Remove unnecessary using System directive Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com> --- .../src/System/Text/Json/Schema/JsonSchemaExporter.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs index f95312d886741e..ab69c1709c72e9 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; From 7dac5523245a8bfa71372c6fe9c9dcacd626510b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Jul 2026 11:00:13 +0000 Subject: [PATCH 7/8] Revert test property name change; keep existing test unmodified Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com> --- .../tests/Common/JsonSchemaExporterTests.TestTypes.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs b/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs index 332902b178736a..065f18e501d5ec 100644 --- a/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs +++ b/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs @@ -1152,7 +1152,7 @@ of the type which points to the first occurrence. */ { "type": ["object","null"], "properties": { - "~/path/to/value ^": { + "~/path/to/value": { "type": "object", "properties": { "Value" : {"type":"integer"}, @@ -1160,7 +1160,7 @@ of the type which points to the first occurrence. */ "type": ["object","null"], "properties": { "Value" : {"type":"integer"}, - "Next": {"$ref":"#/properties/~0~1path~1to~1value%20%5E/properties/Next"} + "Next": {"$ref":"#/properties/~0~1path~1to~1value/properties/Next"} } } } @@ -1610,7 +1610,7 @@ public ClassWithComponentModelAttributes(string stringValue, [DefaultValue(42)] public class ClassWithJsonPointerEscapablePropertyNames { - [JsonPropertyName("~/path/to/value ^")] + [JsonPropertyName("~/path/to/value")] public PocoWithRecursiveMembers Value { get; set; } } From c5e1dab2de158544a2ba9aa474ec52a5685fd045 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 17 Jul 2026 10:43:32 +0000 Subject: [PATCH 8/8] Add regression test exercising reported hello%20world $ref issue Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com> --- .../JsonSchemaExporterTests.TestTypes.cs | 29 +++++++++++++++++++ .../Serialization/JsonSchemaExporterTests.cs | 1 + 2 files changed, 30 insertions(+) diff --git a/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs b/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs index 065f18e501d5ec..9d5be48d5fe245 100644 --- a/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs +++ b/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs @@ -1169,6 +1169,29 @@ of the type which points to the first occurrence. */ } """); + yield return new TestData( + Value: new ClassWithPropertyNameRequiringFragmentEncoding { Value = new() }, + ExpectedJsonSchema: """ + { + "type": ["object","null"], + "properties": { + "hello%20world": { + "type": "object", + "properties": { + "Value" : {"type":"integer"}, + "Next": { + "type": ["object","null"], + "properties": { + "Value" : {"type":"integer"}, + "Next": {"$ref":"#/properties/hello%2520world/properties/Next"} + } + } + } + } + } + } + """); + yield return new TestData( Value: new(value: null), AdditionalValues: [new(true), new(42), new(""), new(new object()), new(Array.Empty())], @@ -1614,6 +1637,12 @@ public class ClassWithJsonPointerEscapablePropertyNames public PocoWithRecursiveMembers Value { get; set; } } + public class ClassWithPropertyNameRequiringFragmentEncoding + { + [JsonPropertyName("hello%20world")] + public PocoWithRecursiveMembers Value { get; set; } + } + public class ClassWithOptionalObjectParameter(object? value = null) { public object? Value { get; } = value; diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/JsonSchemaExporterTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/JsonSchemaExporterTests.cs index f4cf65cb00a8b9..9dc8bc2131d925 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/JsonSchemaExporterTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/JsonSchemaExporterTests.cs @@ -115,6 +115,7 @@ public sealed partial class JsonSchemaExporterTests_SourceGen() [JsonSerializable(typeof(PocoCombiningPolymorphicTypeAndDerivedTypes))] [JsonSerializable(typeof(ClassWithComponentModelAttributes))] [JsonSerializable(typeof(ClassWithJsonPointerEscapablePropertyNames))] + [JsonSerializable(typeof(ClassWithPropertyNameRequiringFragmentEncoding))] [JsonSerializable(typeof(ClassWithOptionalObjectParameter))] [JsonSerializable(typeof(ClassWithPropertiesUsingCustomConverters))] // Collection types