From 039471187061315725b4b528f8aeb7920280b49c Mon Sep 17 00:00:00 2001 From: Eirik Tsarpalis Date: Fri, 3 Jul 2026 11:11:54 +0300 Subject: [PATCH 1/3] Re-enable source generator support for inaccessible [JsonInclude] members The System.Text.Json source generator supports inaccessible members via UnsafeAccessor (net8+) or a reflection fallback (.NET Framework). Support for inaccessible members annotated with [JsonInclude] was intentionally disabled in #124650 because a workaround in the MCP SDK relied on the omission. That dependency has since been removed (modelcontextprotocol/csharp-sdk#1686), so this re-enables full support. - The parser no longer forces HasJsonInclude = false for inaccessible [JsonInclude] members and no longer reports SYSLIB1038. - The SYSLIB1038 diagnostic descriptor and its resx/xlf strings are removed; the diagnostic ID remains documented so it is never reused. - Behavior tests now assert full round-trip support uniformly across reflection and source-gen; the disabled-behavior source-gen overrides are removed and the UnsafeAccessors_PrivateProperties baselines are regenerated for both netcoreapp (UnsafeAccessor) and net462 (reflection). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- ...onSourceGenerator.DiagnosticDescriptors.cs | 8 - .../gen/JsonSourceGenerator.Parser.cs | 37 +-- .../gen/Resources/Strings.resx | 6 - .../gen/Resources/xlf/Strings.cs.xlf | 10 - .../gen/Resources/xlf/Strings.de.xlf | 10 - .../gen/Resources/xlf/Strings.es.xlf | 10 - .../gen/Resources/xlf/Strings.fr.xlf | 10 - .../gen/Resources/xlf/Strings.it.xlf | 10 - .../gen/Resources/xlf/Strings.ja.xlf | 10 - .../gen/Resources/xlf/Strings.ko.xlf | 10 - .../gen/Resources/xlf/Strings.pl.xlf | 10 - .../gen/Resources/xlf/Strings.pt-BR.xlf | 10 - .../gen/Resources/xlf/Strings.ru.xlf | 10 - .../gen/Resources/xlf/Strings.tr.xlf | 10 - .../gen/Resources/xlf/Strings.zh-Hans.xlf | 10 - .../gen/Resources/xlf/Strings.zh-Hant.xlf | 10 - ...pertyVisibilityTests.NonPublicAccessors.cs | 53 ++-- .../Serialization/PropertyVisibilityTests.cs | 280 ------------------ ...m.Text.Json.SourceGeneration.Tests.targets | 3 +- .../net462/MyContext.PrivateProps.g.cs.txt | 23 +- .../net462/MyContext.PropertyNames.g.cs.txt | 2 + .../MyContext.PrivateProps.g.cs.txt | 23 +- .../MyContext.PropertyNames.g.cs.txt | 2 + .../JsonSourceGeneratorDiagnosticsTests.cs | 27 +- .../JsonSourceGeneratorOutputTests.cs | 2 +- 25 files changed, 65 insertions(+), 531 deletions(-) diff --git a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.DiagnosticDescriptors.cs b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.DiagnosticDescriptors.cs index 7570457a81027e..5be4c1ff76d97f 100644 --- a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.DiagnosticDescriptors.cs +++ b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.DiagnosticDescriptors.cs @@ -68,14 +68,6 @@ internal static class DiagnosticDescriptors defaultSeverity: DiagnosticSeverity.Error, isEnabledByDefault: true); - public static DiagnosticDescriptor InaccessibleJsonIncludePropertiesNotSupported { get; } = DiagnosticDescriptorHelper.Create( - id: "SYSLIB1038", - title: new LocalizableResourceString(nameof(SR.InaccessibleJsonIncludePropertiesNotSupportedTitle), SR.ResourceManager, typeof(FxResources.System.Text.Json.SourceGeneration.SR)), - messageFormat: new LocalizableResourceString(nameof(SR.InaccessibleJsonIncludePropertiesNotSupportedFormat), SR.ResourceManager, typeof(FxResources.System.Text.Json.SourceGeneration.SR)), - category: JsonConstants.SystemTextJsonSourceGenerationName, - defaultSeverity: DiagnosticSeverity.Warning, - isEnabledByDefault: true); - public static DiagnosticDescriptor PolymorphismNotSupported { get; } = DiagnosticDescriptorHelper.Create( id: "SYSLIB1039", title: new LocalizableResourceString(nameof(SR.FastPathPolymorphismNotSupportedTitle), SR.ResourceManager, typeof(FxResources.System.Text.Json.SourceGeneration.SR)), diff --git a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs index 9d80e95598a98c..48fca3eb5b224a 100644 --- a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs +++ b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs @@ -1986,12 +1986,6 @@ void AddMember( AddPropertyWithConflictResolution(propertySpec, memberInfo, propertyIndex: properties.Count, ref state); properties.Add(propertySpec); - - // Note: ParsePropertyGenerationSpec intentionally does not mark inaccessible - // [JsonInclude] members as invalid for fast-path generation. Some callers rely - // on that omission to source-generate against experimental APIs without - // introducing new warnings until https://github.com/dotnet/runtime/issues/124889 - // is completed. } bool PropertyIsOverriddenAndIgnored(IPropertySymbol property, Dictionary? ignoredMembers) @@ -2162,16 +2156,10 @@ private bool IsValidDataExtensionPropertyType(ITypeSymbol type) out bool isRequired, out bool canUseGetter, out bool canUseSetter, - out bool hasJsonIncludeButIsInaccessible, out bool setterIsInitOnly, out bool isGetterNonNullable, out bool isSetterNonNullable); - if (hasJsonIncludeButIsInaccessible) - { - ReportDiagnostic(DiagnosticDescriptors.InaccessibleJsonIncludePropertiesNotSupported, memberInfo.GetLocation(), declaringType.Name, memberInfo.Name); - } - if (isExtensionData) { if (typeHasExtensionDataProperty) @@ -2187,11 +2175,13 @@ private bool IsValidDataExtensionPropertyType(ITypeSymbol type) typeHasExtensionDataProperty = true; } - if ((!canUseGetter && !canUseSetter && !hasJsonIncludeButIsInaccessible) || + if ((!canUseGetter && !canUseSetter && !hasJsonInclude) || !IsSymbolAccessibleWithin(memberType, within: contextType)) { // Skip the member if either of the two conditions hold - // 1. Member has no accessible getters or setters (but is not marked with JsonIncludeAttribute since we need to throw a runtime exception) OR + // 1. Member has no accessible getters or setters and is not annotated with + // JsonIncludeAttribute (inaccessible [JsonInclude] members are read/written + // using UnsafeAccessor or reflection) OR // 2. The member type is not accessible within the generated context. return null; } @@ -2244,10 +2234,7 @@ private bool IsValidDataExtensionPropertyType(ITypeSymbol type) NumberHandling = numberHandling, ObjectCreationHandling = objectCreationHandling, Order = order, - // TODO: remove the inaccessibility check once https://github.com/dotnet/runtime/issues/124889 - // is complete; some callers currently rely on this omission when source-generating - // against experimental APIs (tracking: https://github.com/dotnet/runtime/issues/88519). - HasJsonInclude = hasJsonInclude && !hasJsonIncludeButIsInaccessible, + HasJsonInclude = hasJsonInclude, CanUseUnsafeAccessors = _knownSymbols.UnsafeAccessorAttributeType is not null && (memberInfo.ContainingType is not INamedTypeSymbol { IsGenericType: true } || _knownSymbols.SupportsGenericUnsafeAccessors), @@ -2396,7 +2383,6 @@ private void ProcessMember( out bool isRequired, out bool canUseGetter, out bool canUseSetter, - out bool hasJsonIncludeButIsInaccessible, out bool isSetterInitOnly, out bool isGetterNonNullable, out bool isSetterNonNullable) @@ -2406,7 +2392,6 @@ private void ProcessMember( isRequired = false; canUseGetter = false; canUseSetter = false; - hasJsonIncludeButIsInaccessible = false; isSetterInitOnly = false; isGetterNonNullable = false; isSetterNonNullable = false; @@ -2429,10 +2414,6 @@ private void ProcessMember( isAccessible = true; canUseGetter = hasJsonInclude; } - else - { - hasJsonIncludeButIsInaccessible = hasJsonInclude; - } } if (propertyInfo.SetMethod is { } setMethod) @@ -2449,10 +2430,6 @@ private void ProcessMember( isAccessible = true; canUseSetter = hasJsonInclude; } - else - { - hasJsonIncludeButIsInaccessible = hasJsonInclude; - } } else { @@ -2478,10 +2455,6 @@ private void ProcessMember( canUseGetter = hasJsonInclude; canUseSetter = hasJsonInclude && !isReadOnly; } - else - { - hasJsonIncludeButIsInaccessible = hasJsonInclude; - } fieldInfo.ResolveNullabilityAnnotations(out isGetterNonNullable, out isSetterNonNullable); break; diff --git a/src/libraries/System.Text.Json/gen/Resources/Strings.resx b/src/libraries/System.Text.Json/gen/Resources/Strings.resx index 53e5b8b6da5c33..446fe72efc6ca2 100644 --- a/src/libraries/System.Text.Json/gen/Resources/Strings.resx +++ b/src/libraries/System.Text.Json/gen/Resources/Strings.resx @@ -153,12 +153,6 @@ Data extension property type invalid. - - Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. - - - The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. - 'JsonDerivedTypeAttribute' is not supported in 'JsonSourceGenerationMode.Serialization'. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.cs.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.cs.xlf index dd58a77601950d..b55f6d6983d368 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.cs.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.cs.xlf @@ -52,16 +52,6 @@ Atribut JsonDerivedTypeAttribute se v JsonSourceGenerationMode.Serialization nepodporuje. - - The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. - Člen {0}.{1} má anotaci od JsonIncludeAttribute, ale není pro zdrojový generátor viditelný. - - - - Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. - Nepřístupné vlastnosti anotované s JsonIncludeAttribute se v režimu generování zdroje nepodporují. - - The 'JsonConverterAttribute' type '{0}' specified on member '{1}' is not a converter type or does not contain an accessible parameterless constructor. Typ JsonConverterAttribute {0} specifikovaný u členu {1} není typem konvertoru nebo neobsahuje přístupný konstruktor bez parametrů. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.de.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.de.xlf index b82c12772fc563..c0d0eaef022cfb 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.de.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.de.xlf @@ -52,16 +52,6 @@ „JsonDerivedTypeAttribute“ wird in „JsonSourceGenerationMode.Serialization“ nicht unterstützt. - - The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. - Der Member "{0}. {1}" wurde mit dem JsonIncludeAttribute versehen, ist jedoch für den Quellgenerator nicht sichtbar. - - - - Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. - Nicht zugängliche Eigenschaften, die mit dem JsonIncludeAttribute versehen sind, werden im Quellgenerierungsmodus nicht unterstützt. - - The 'JsonConverterAttribute' type '{0}' specified on member '{1}' is not a converter type or does not contain an accessible parameterless constructor. Der für den Member "{1}" angegebene JsonConverterAttribute-Typ "{0}" ist kein Konvertertyp oder enthält keinen parameterlosen Konstruktor, auf den zugegriffen werden kann. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.es.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.es.xlf index 42fbfa808390e7..c80268035c6e94 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.es.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.es.xlf @@ -52,16 +52,6 @@ \"JsonDerivedTypeAttribute\" no se admite en \"JsonSourceGenerationMode.Serialization\". - - The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. - El miembro '{0}.{1}' se ha anotado con JsonIncludeAttribute, pero no es visible para el generador de origen. - - - - Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. - Las propiedades inaccesibles anotadas con JsonIncludeAttribute no se admiten en el modo de generación de origen. - - The 'JsonConverterAttribute' type '{0}' specified on member '{1}' is not a converter type or does not contain an accessible parameterless constructor. El tipo “JsonConverterAttribute” “{0}” especificado en el miembro “{1}” no es un tipo de convertidor o no contiene un constructor sin parámetros accesible. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.fr.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.fr.xlf index a34e720723f0b2..3f3a6e8c87beb5 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.fr.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.fr.xlf @@ -52,16 +52,6 @@ « JsonDerivedTypeAttribute » n’est pas pris en charge dans « JsonSourceGenerationMode.Serialization ». - - The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. - Le membre '{0}.{1}' a été annoté avec JsonIncludeAttribute mais n’est pas visible pour le générateur source. - - - - Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. - Les propriétés inaccessibles annotées avec JsonIncludeAttribute ne sont pas prises en charge en mode de génération de source. - - The 'JsonConverterAttribute' type '{0}' specified on member '{1}' is not a converter type or does not contain an accessible parameterless constructor. Le type 'JsonConverterAttribute' '{0}' spécifié sur le membre '{1}' n’est pas un type convertisseur ou ne contient pas de constructeur sans paramètre accessible. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.it.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.it.xlf index 469686d5e19f8e..21a23d538faefa 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.it.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.it.xlf @@ -52,16 +52,6 @@ 'JsonDerivedTypeAttribute' non è supportato in 'JsonSourceGenerationMode.Serialization'. - - The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. - Il membro ' {0}.{1}' è stato annotato con JsonIncludeAttribute ma non è visibile al generatore di origine. - - - - Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. - Le proprietà inaccessibili annotate con JsonIncludeAttribute non sono supportate nella modalità di generazione di origine. - - The 'JsonConverterAttribute' type '{0}' specified on member '{1}' is not a converter type or does not contain an accessible parameterless constructor. Il tipo 'JsonConverterAttribute' '{0}' specificato nel membro '{1}' non è un tipo di convertitore o non contiene un costruttore senza parametri accessibile. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ja.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ja.xlf index 3863bb2b28bb53..db1cbf88bda348 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ja.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ja.xlf @@ -52,16 +52,6 @@ 'JsonDerivedTypeAttribute' は 'JsonSourceGenerationMode.Serialization' ではサポートされていません。 - - The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. - メンバー '{0}.{1}' には、JsonIncludeAttribute で注釈が付けられていますが、ソース ジェネレーターには表示されません。 - - - - Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. - JsonIncludeAttribute で注釈が付けられたアクセスできないプロパティは、ソース生成モードではサポートされていません。 - - The 'JsonConverterAttribute' type '{0}' specified on member '{1}' is not a converter type or does not contain an accessible parameterless constructor. メンバー '{1}' で指定されている 'JsonConverterAttribute' 型 '{0}' はコンバーター型ではないか、アクセス可能なパラメーターなしのコンストラクターを含んでいません。 diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ko.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ko.xlf index d127c4ad67eb7b..40625805982421 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ko.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ko.xlf @@ -52,16 +52,6 @@ 'JsonSourceGenerationMode.Serialization'에서는 'JsonDerivedTypeAttribute'가 지원되지 않습니다. - - The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. - 멤버 '{0}.{1}'이(가) JsonIncludeAttribute로 주석 처리되었지만 원본 생성기에는 표시되지 않습니다. - - - - Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. - JsonIncludeAttribute로 주석 처리된 액세스할 수 없는 속성은 원본 생성 모드에서 지원되지 않습니다. - - The 'JsonConverterAttribute' type '{0}' specified on member '{1}' is not a converter type or does not contain an accessible parameterless constructor. '{1}' 멤버에 지정된 'JsonConverterAttribute' 형식 '{0}'이(가) 변환기 형식이 아니거나 액세스 가능한 매개 변수가 없는 생성자를 포함하지 않습니다. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pl.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pl.xlf index 76a5941f660295..17dffc837a5103 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pl.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pl.xlf @@ -52,16 +52,6 @@ Atrybut „JsonDerivedTypeAttribute” nie jest obsługiwany w elemecie „JsonSourceGenerationMode.Serialization”. - - The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. - Składowa "{0}. {1}" jest adnotowana za pomocą atrybutu JsonIncludeAttribute, ale nie jest widoczna dla generatora źródła. - - - - Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. - Niedostępne właściwości adnotowane za pomocą atrybutu JsonIncludeAttribute nie są obsługiwane w trybie generowania źródła. - - The 'JsonConverterAttribute' type '{0}' specified on member '{1}' is not a converter type or does not contain an accessible parameterless constructor. Typ „{0}” „JsonConverterAttribute” określony w przypadku składowej „{1}” nie jest typem konwertera lub nie zawiera dostępnego konstruktora bez parametrów. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pt-BR.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pt-BR.xlf index 26ebe55ffc7f40..f9438ee48ed62a 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pt-BR.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pt-BR.xlf @@ -52,16 +52,6 @@ 'JsonDerivedTypeAttribute' não tem suporte em 'JsonSourceGenerationMode.Serialization'. - - The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. - O membro '{0}.{1}' foi anotado com o JsonIncludeAttribute, mas não é visível para o gerador de origem. - - - - Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. - Propriedades inacessíveis anotadas com JsonIncludeAttribute não são suportadas no modo de geração de origem. - - The 'JsonConverterAttribute' type '{0}' specified on member '{1}' is not a converter type or does not contain an accessible parameterless constructor. O tipo "JsonConverterAttribute" "{0}" especificado no membro "{1}" não é um tipo de conversor ou não contém um construtor sem parâmetros acessível. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ru.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ru.xlf index 779233795a57b4..46daaa8228822e 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ru.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ru.xlf @@ -52,16 +52,6 @@ Атрибут JsonDerivedTypeAttribute не поддерживается в \"JsonSourceGenerationMode.Serialization\". - - The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. - Элемент "{0}.{1}" аннотирован с использованием класса JsonIncludeAttribute, но генератор исходного кода не обнаруживает этот элемент. - - - - Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. - Недоступные свойства, аннотированные с использованием класса JsonIncludeAttribute, не поддерживаются в режиме создания исходного кода. - - The 'JsonConverterAttribute' type '{0}' specified on member '{1}' is not a converter type or does not contain an accessible parameterless constructor. Тип "JsonConverterAttribute" "{0}", указанный в элементе "{1}", не является типом преобразователя или не содержит доступного конструктора без параметров. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.tr.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.tr.xlf index 09310022d2c685..961644457743a8 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.tr.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.tr.xlf @@ -52,16 +52,6 @@ 'JsonSourceGenerationMode.Serialization' içinde 'JsonDerivedTypeAttribute' desteklenmiyor. - - The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. - '{0}.{1}' üyesine JsonIncludeAttribute notu eklendi ancak bu üye kaynak oluşturucu tarafından görülmüyor. - - - - Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. - JsonIncludeAttribute notu eklenmiş erişilemeyen özellikler kaynak oluşturma modunda desteklenmiyor. - - The 'JsonConverterAttribute' type '{0}' specified on member '{1}' is not a converter type or does not contain an accessible parameterless constructor. '{1}' üyesi üzerinde belirtilen 'JsonConverterAttribute' '{0}' türü dönüştürücü türü değil veya erişilebilir parametresiz bir oluşturucu içermiyor. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hans.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hans.xlf index d2ff1f2c3cae86..bba5d574bb8539 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hans.xlf @@ -52,16 +52,6 @@ \"JsonSourceGenerationMode.Serialization\" 中不支持 \"JsonDerivedTypeAttribute\"。 - - The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. - 已使用 JsonIncludeAttribute 注释成员“{0}.{1}”,但对源生成器不可见。 - - - - Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. - 源生成模式不支持使用 JsonIncludeAttribute 注释的不可访问属性。 - - The 'JsonConverterAttribute' type '{0}' specified on member '{1}' is not a converter type or does not contain an accessible parameterless constructor. 在成员 "{1}" 上指定的 "JsonConverterAttribute" 类型 "{0}" 不是转换器类型或不包含可访问的无参数构造函数。 diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hant.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hant.xlf index f4d26b17872fe0..2f64e9918c993d 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hant.xlf @@ -52,16 +52,6 @@ 'JsonSourceGenerationMode.Serialization' 中不支援 'JsonDerivedTypeAttribute'。 - - The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. - 成員 '{0}.{1}' 已經以 JsonIncludeAttribute 標註,但對來源產生器是不可見的。 - - - - Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. - 來源產生模式不支援以 JsonIncludeAttribute 標註的無法存取屬性。 - - The 'JsonConverterAttribute' type '{0}' specified on member '{1}' is not a converter type or does not contain an accessible parameterless constructor. 成員 '{1}' 上指定的 'JsonConverterAttribute' 類型 '{0}' 不是轉換器類型,或不包含可存取的無參數建構函式。 diff --git a/src/libraries/System.Text.Json/tests/Common/PropertyVisibilityTests.NonPublicAccessors.cs b/src/libraries/System.Text.Json/tests/Common/PropertyVisibilityTests.NonPublicAccessors.cs index bc903071112aaa..31100ce277a3d7 100644 --- a/src/libraries/System.Text.Json/tests/Common/PropertyVisibilityTests.NonPublicAccessors.cs +++ b/src/libraries/System.Text.Json/tests/Common/PropertyVisibilityTests.NonPublicAccessors.cs @@ -352,43 +352,26 @@ public class ClassWithMixedPropertyAccessors_PropertyAttributes } [Theory] - [InlineData(typeof(ClassWithPrivateProperty_WithJsonIncludeProperty), false)] - [InlineData(typeof(ClassWithInternalProperty_WithJsonIncludeProperty), true)] - [InlineData(typeof(ClassWithProtectedProperty_WithJsonIncludeProperty), false)] - [InlineData(typeof(ClassWithPrivateField_WithJsonIncludeProperty), false)] - [InlineData(typeof(ClassWithInternalField_WithJsonIncludeProperty), true)] - [InlineData(typeof(ClassWithProtectedField_WithJsonIncludeProperty), false)] - [InlineData(typeof(ClassWithPrivate_InitOnlyProperty_WithJsonIncludeProperty), false)] - [InlineData(typeof(ClassWithInternal_InitOnlyProperty_WithJsonIncludeProperty), true)] - [InlineData(typeof(ClassWithProtected_InitOnlyProperty_WithJsonIncludeProperty), false)] - public virtual async Task NonPublicProperty_JsonInclude_WorksAsExpected([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type type, bool isAccessibleBySourceGen) - { - if (!Serializer.IsSourceGeneratedSerializer || isAccessibleBySourceGen) - { - string json = """{"MyString":"value"}"""; - MemberInfo memberInfo = type.GetMember("MyString", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)[0]; + [InlineData(typeof(ClassWithPrivateProperty_WithJsonIncludeProperty))] + [InlineData(typeof(ClassWithInternalProperty_WithJsonIncludeProperty))] + [InlineData(typeof(ClassWithProtectedProperty_WithJsonIncludeProperty))] + [InlineData(typeof(ClassWithPrivateField_WithJsonIncludeProperty))] + [InlineData(typeof(ClassWithInternalField_WithJsonIncludeProperty))] + [InlineData(typeof(ClassWithProtectedField_WithJsonIncludeProperty))] + [InlineData(typeof(ClassWithPrivate_InitOnlyProperty_WithJsonIncludeProperty))] + [InlineData(typeof(ClassWithInternal_InitOnlyProperty_WithJsonIncludeProperty))] + [InlineData(typeof(ClassWithProtected_InitOnlyProperty_WithJsonIncludeProperty))] + public virtual async Task NonPublicProperty_JsonInclude_WorksAsExpected([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type type) + { + string json = """{"MyString":"value"}"""; + MemberInfo memberInfo = type.GetMember("MyString", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)[0]; - object result = await Serializer.DeserializeWrapper("""{"MyString":"value"}""", type); - Assert.IsType(type, result); - Assert.Equal(memberInfo is PropertyInfo p ? p.GetValue(result) : ((FieldInfo)memberInfo).GetValue(result), "value"); + object result = await Serializer.DeserializeWrapper("""{"MyString":"value"}""", type); + Assert.IsType(type, result); + Assert.Equal(memberInfo is PropertyInfo p ? p.GetValue(result) : ((FieldInfo)memberInfo).GetValue(result), "value"); - string actualJson = await Serializer.SerializeWrapper(result, type); - Assert.Equal(json, actualJson); - } - else - { - InvalidOperationException ex = await Assert.ThrowsAsync(async () => await Serializer.DeserializeWrapper("{}", type)); - string exAsStr = ex.ToString(); - Assert.Contains("MyString", exAsStr); - Assert.Contains(type.ToString(), exAsStr); - Assert.Contains("JsonIncludeAttribute", exAsStr); - - ex = await Assert.ThrowsAsync(async () => await Serializer.SerializeWrapper(Activator.CreateInstance(type), type)); - exAsStr = ex.ToString(); - Assert.Contains("MyString", exAsStr); - Assert.Contains(type.ToString(), exAsStr); - Assert.Contains("JsonIncludeAttribute", exAsStr); - } + string actualJson = await Serializer.SerializeWrapper(result, type); + Assert.Equal(json, actualJson); } public class ClassWithPrivateProperty_WithJsonIncludeProperty diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/PropertyVisibilityTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/PropertyVisibilityTests.cs index c7bd164df930ec..bc836b1dbd4aed 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/PropertyVisibilityTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/PropertyVisibilityTests.cs @@ -46,286 +46,6 @@ void ValidateInvalidOperationException() } } - [Fact] - public override async Task Honor_JsonSerializablePropertyAttribute_OnProperties() - { - // Inaccessible [JsonInclude] members are ignored (https://github.com/dotnet/runtime/issues/124889). - // MyInt (public get, private set) and MyString (public get, internal set) serialize normally. - // MyFloat (private get, public set) and MyUri (internal get, public set) lack getter delegates. - string json = """{"MyInt":1,"MyString":"Hello","MyFloat":2,"MyUri":"https://microsoft.com"}"""; - var obj = await Serializer.DeserializeWrapper(json); - Assert.Equal(0, obj.MyInt); - Assert.Equal("Hello", obj.MyString); - - string serialized = await Serializer.SerializeWrapper(obj); - Assert.Contains(@"""MyString"":""Hello""", serialized); - Assert.Contains(@"""MyUri"":""https://microsoft.com""", serialized); - } - - [Theory] - [InlineData(typeof(Class_PropertyWith_PrivateInitOnlySetter_WithAttribute))] - [InlineData(typeof(Class_PropertyWith_InternalInitOnlySetter_WithAttribute))] - [InlineData(typeof(Class_PropertyWith_ProtectedInitOnlySetter_WithAttribute))] - public override async Task NonPublicInitOnlySetter_With_JsonInclude([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type type) - { - // Inaccessible [JsonInclude] members are ignored (https://github.com/dotnet/runtime/issues/124889). - // All types have public getter so serialization works; internal setter type can also deserialize. - bool isDeserializationSupported = type == typeof(Class_PropertyWith_InternalInitOnlySetter_WithAttribute); - - object obj = Activator.CreateInstance(type); - type.GetProperty("MyInt").SetValue(obj, 1); - Assert.Equal("""{"MyInt":1}""", await Serializer.SerializeWrapper(obj, type)); - - if (isDeserializationSupported) - { - obj = await Serializer.DeserializeWrapper("""{"MyInt":1}""", type); - Assert.Equal(1, (int)type.GetProperty("MyInt").GetValue(obj)); - } - else - { - obj = await Serializer.DeserializeWrapper("""{"MyInt":1}""", type); - Assert.Equal(0, (int)type.GetProperty("MyInt").GetValue(obj)); - } - } - - [Fact] - public override async Task HonorCustomConverter_UsingPrivateSetter() - { - // Inaccessible [JsonInclude] members are ignored (https://github.com/dotnet/runtime/issues/124889). - // MyEnum (private get, public set): setter works, getter excluded. - // MyInt (public get, private set): getter works (with converter), setter excluded. - var options = new JsonSerializerOptions(); - options.Converters.Add(new JsonStringEnumConverter()); - - string json = """{"MyEnum":"AnotherValue","MyInt":2}"""; - var obj = await Serializer.DeserializeWrapper(json, options); - Assert.Equal(MySmallEnum.AnotherValue, obj.GetMyEnum); - Assert.Equal(0, obj.MyInt); - } - - [Fact] - public override async Task Public_And_NonPublicPropertyAccessors_PropertyAttributes() - { - // Inaccessible [JsonInclude] members are ignored (https://github.com/dotnet/runtime/issues/124889). - // Z (private get, public set) has no getter delegate so won't appear in serialization output. - string json = """{"W":1,"X":2,"Y":3,"Z":4}"""; - var obj = await Serializer.DeserializeWrapper(json); - Assert.Equal(1, obj.W); - Assert.Equal(2, obj.X); - Assert.Equal(3, obj.Y); - Assert.Equal(4, obj.GetZ); - - string serialized = await Serializer.SerializeWrapper(obj); - Assert.Contains(@"""W"":1", serialized); - Assert.Contains(@"""X"":2", serialized); - Assert.Contains(@"""Y"":3", serialized); - Assert.DoesNotContain(@"""Z"":", serialized); - } - - [Fact] - public override async Task HonorJsonPropertyName_PrivateGetter() - { - // Inaccessible [JsonInclude] members are ignored (https://github.com/dotnet/runtime/issues/124889). - // MyEnum (private get, public set) won't serialize (no getter delegate). - string json = """{"prop1":1}"""; - var obj = await Serializer.DeserializeWrapper(json); - Assert.Equal(MySmallEnum.AnotherValue, obj.GetProxy()); - - string serialized = await Serializer.SerializeWrapper(obj); - Assert.DoesNotContain("prop1", serialized); - } - - [Fact] - public override async Task HonorJsonPropertyName_PrivateSetter() - { - // Inaccessible [JsonInclude] members are ignored (https://github.com/dotnet/runtime/issues/124889). - // MyInt (public get, private set) serializes but can't be deserialized. - var obj = new StructWithPropertiesWithJsonPropertyName_PrivateSetter(); - obj.SetProxy(2); - Assert.Equal("""{"prop2":2}""", await Serializer.SerializeWrapper(obj)); - - obj = await Serializer.DeserializeWrapper("""{"prop2":2}"""); - Assert.Equal(0, obj.MyInt); - } - - public override async Task NonPublicProperty_JsonInclude_WorksAsExpected([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type type, bool isAccessibleBySourceGen) - { - // Inaccessible [JsonInclude] members are ignored (https://github.com/dotnet/runtime/issues/124889). - if (isAccessibleBySourceGen) - { - await base.NonPublicProperty_JsonInclude_WorksAsExpected(type, isAccessibleBySourceGen); - } - else - { - object result = await Serializer.DeserializeWrapper("""{"MyString":"value"}""", type); - Assert.IsType(type, result); - - string json = await Serializer.SerializeWrapper(result, type); - Assert.Equal("{}", json); - } - } - - // The following tests validate that inaccessible [JsonInclude] members are ignored - // until https://github.com/dotnet/runtime/issues/124889 is complete (tracking: https://github.com/dotnet/runtime/issues/88519). - - [Fact] - public override async Task JsonInclude_PrivateProperties_CanRoundtrip() - { - var obj = ClassWithPrivateJsonIncludeProperties_Roundtrip.Create("Test", 25); - string json = await Serializer.SerializeWrapper(obj); - Assert.Equal("{}", json); - } - - [Fact] - public override async Task JsonInclude_ProtectedProperties_CanRoundtrip() - { - var obj = ClassWithProtectedJsonIncludeProperties_Roundtrip.Create("Test", 25); - string json = await Serializer.SerializeWrapper(obj); - Assert.Equal("{}", json); - } - - [Fact] - public override async Task JsonInclude_MixedAccessibility_AllPropertiesRoundtrip() - { - string json = """{"PublicProp":1,"InternalProp":2,"PrivateProp":3,"ProtectedProp":4}"""; - var deserialized = await Serializer.DeserializeWrapper(json); - Assert.Equal(1, deserialized.PublicProp); - Assert.Equal(2, deserialized.InternalProp); - Assert.Equal(0, deserialized.GetPrivateProp()); - Assert.Equal(0, deserialized.GetProtectedProp()); - - string actualJson = await Serializer.SerializeWrapper(deserialized); - Assert.Contains(@"""PublicProp"":1", actualJson); - Assert.Contains(@"""InternalProp"":2", actualJson); - Assert.DoesNotContain("PrivateProp", actualJson); - Assert.DoesNotContain("ProtectedProp", actualJson); - } - - [Fact] - public override async Task JsonInclude_PrivateInitOnlyProperties_PreservesDefaults() - { - var deserialized = await Serializer.DeserializeWrapper("{}"); - Assert.Equal("DefaultName", deserialized.Name); - Assert.Equal(42, deserialized.Number); - - deserialized = await Serializer.DeserializeWrapper("""{"Name":"Override","Number":100}"""); - Assert.Equal("DefaultName", deserialized.Name); - Assert.Equal(42, deserialized.Number); - } - - [Fact] - public override async Task JsonInclude_PrivateGetterProperties_CanSerialize() - { - var obj = new ClassWithJsonIncludePrivateGetterProperties { Name = "Test", Number = 99 }; - string json = await Serializer.SerializeWrapper(obj); - Assert.DoesNotContain("Name", json); - Assert.DoesNotContain("Number", json); - } - - [Fact] - public override async Task JsonInclude_PrivateProperties_EmptyJson_DeserializesToDefault() - { - var deserialized = await Serializer.DeserializeWrapper("{}"); - Assert.Equal("default", deserialized.GetName()); - Assert.Equal(0, deserialized.GetAge()); - } - - [Fact] - public override async Task JsonInclude_StructWithPrivateProperties_CanRoundtrip() - { - var obj = StructWithJsonIncludePrivateProperties.Create("Hello", 42); - string json = await Serializer.SerializeWrapper(obj); - Assert.Equal("{}", json); - } - - [Fact] - public override async Task JsonInclude_GenericType_PrivateProperties_CanRoundtrip() - { - var obj = GenericClassWithPrivateJsonIncludeProperties.Create(42, "test"); - string json = await Serializer.SerializeWrapper(obj); - Assert.Equal("{}", json); - } - - [Fact] - public override void InitOnlyProperties_ExposesSetterDelegate() - { - JsonTypeInfo typeInfo = Serializer.GetTypeInfo(typeof(ClassWithJsonIncludePrivateInitOnlyProperties)); - - JsonPropertyInfo nameProp = typeInfo.Properties.Single(p => p.Name == "Name"); - Assert.NotNull(nameProp.Get); - Assert.Null(nameProp.Set); - - JsonPropertyInfo numberProp = typeInfo.Properties.Single(p => p.Name == "Number"); - Assert.NotNull(numberProp.Get); - Assert.Null(numberProp.Set); - } - - public override void NonPublicInitOnlyJsonIncludeProperties_HaveNoAssociatedParameterInfo(Type type) - { - JsonTypeInfo typeInfo = Serializer.GetTypeInfo(type); - bool isAccessible = type.Name.Contains("Internal"); - if (isAccessible) - { - JsonPropertyInfo prop = typeInfo.Properties.Single(p => p.Name == "MyString"); - Assert.NotNull(prop.Get); - Assert.NotNull(prop.Set); - Assert.Null(prop.AssociatedParameter); - } - else - { - Assert.DoesNotContain(typeInfo.Properties, p => p.Name == "MyString"); - } - } - - [Fact] - public override void PrivateJsonIncludeProperties_ExposesGetterAndSetterDelegates() - { - JsonTypeInfo typeInfo = Serializer.GetTypeInfo(typeof(ClassWithPrivateJsonIncludeProperties_Roundtrip)); - Assert.Empty(typeInfo.Properties); - } - - [Fact] - public override void PrivateJsonIncludeGetterOnly_ExposesGetterDelegate() - { - JsonTypeInfo typeInfo = Serializer.GetTypeInfo(typeof(ClassWithJsonIncludePrivateGetterProperties)); - - JsonPropertyInfo nameProp = typeInfo.Properties.Single(p => p.Name == "Name"); - Assert.Null(nameProp.Get); - Assert.NotNull(nameProp.Set); - } - - public override void NonPublicJsonIncludeMembers_ExposeGetterAndSetterDelegates(Type type) - { - JsonTypeInfo typeInfo = Serializer.GetTypeInfo(type); - bool isAccessible = type.Name.Contains("Internal"); - if (isAccessible) - { - JsonPropertyInfo prop = typeInfo.Properties.Single(p => p.Name == "MyString"); - Assert.NotNull(prop.Get); - Assert.NotNull(prop.Set); - } - else - { - Assert.DoesNotContain(typeInfo.Properties, p => p.Name == "MyString"); - } - } - - [Fact] - public override void MixedAccessibilityJsonIncludeProperties_AllExposeGetterAndSetterDelegates() - { - JsonTypeInfo typeInfo = Serializer.GetTypeInfo(typeof(ClassWithMixedAccessibilityJsonIncludeProperties)); - Assert.Equal(2, typeInfo.Properties.Count); - Assert.NotNull(typeInfo.Properties.Single(p => p.Name == "PublicProp").Get); - Assert.NotNull(typeInfo.Properties.Single(p => p.Name == "InternalProp").Get); - } - - [Fact] - public override void StructWithPrivateJsonIncludeProperties_ExposesGetterAndSetterDelegates() - { - JsonTypeInfo typeInfo = Serializer.GetTypeInfo(typeof(StructWithJsonIncludePrivateProperties)); - Assert.Empty(typeInfo.Properties); - } - [Fact] public override async Task TestCollectionWithPrivateElementType() { diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/System.Text.Json.SourceGeneration.Tests.targets b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/System.Text.Json.SourceGeneration.Tests.targets index d9d9791b871af6..66ea58048dcb12 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/System.Text.Json.SourceGeneration.Tests.targets +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/System.Text.Json.SourceGeneration.Tests.targets @@ -9,13 +9,12 @@ - - $(NoWarn);SYSLIB0020;SYSLIB0049;SYSLIB1030;SYSLIB1034;SYSLIB1037;SYSLIB1038;SYSLIB1039;SYSLIB1220;SYSLIB1223;SYSLIB1225;SYSLIB1226 + $(NoWarn);SYSLIB0020;SYSLIB0049;SYSLIB1030;SYSLIB1034;SYSLIB1037;SYSLIB1039;SYSLIB1220;SYSLIB1223;SYSLIB1225;SYSLIB1226 true diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/Baselines/UnsafeAccessors_PrivateProperties/net462/MyContext.PrivateProps.g.cs.txt b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/Baselines/UnsafeAccessors_PrivateProperties/net462/MyContext.PrivateProps.g.cs.txt index 9cbe85129e4890..55e2a947262b93 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/Baselines/UnsafeAccessors_PrivateProperties/net462/MyContext.PrivateProps.g.cs.txt +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/Baselines/UnsafeAccessors_PrivateProperties/net462/MyContext.PrivateProps.g.cs.txt @@ -57,10 +57,10 @@ namespace TestApp IsVirtual = false, DeclaringType = typeof(global::TestApp.PrivateProps), Converter = null, - Getter = null, - Setter = null, + Getter = static obj => __get_PrivateProps_Name((global::TestApp.PrivateProps)obj), + Setter = static (obj, value) => __set_PrivateProps_Name((global::TestApp.PrivateProps)obj, value!), IgnoreCondition = null, - HasJsonInclude = false, + HasJsonInclude = true, IsExtensionData = false, NumberHandling = null, PropertyName = "Name", @@ -77,10 +77,10 @@ namespace TestApp IsVirtual = false, DeclaringType = typeof(global::TestApp.PrivateProps), Converter = null, - Getter = null, - Setter = null, + Getter = static obj => __get_PrivateProps_Age((global::TestApp.PrivateProps)obj), + Setter = static (obj, value) => __set_PrivateProps_Age((global::TestApp.PrivateProps)obj, value!), IgnoreCondition = null, - HasJsonInclude = false, + HasJsonInclude = true, IsExtensionData = false, NumberHandling = null, PropertyName = "Age", @@ -105,8 +105,19 @@ namespace TestApp writer.WriteStartObject(); + writer.WriteString(PropName_Name, __get_PrivateProps_Name(((global::TestApp.PrivateProps)value))); + writer.WriteNumber(PropName_Age, __get_PrivateProps_Age(((global::TestApp.PrivateProps)value))); writer.WriteEndObject(); } + + private static global::System.Func? s_get_PrivateProps_Name; + private static string __get_PrivateProps_Name(global::TestApp.PrivateProps obj) => (s_get_PrivateProps_Name ??= (global::System.Func)global::System.Delegate.CreateDelegate(typeof(global::System.Func), typeof(global::TestApp.PrivateProps).GetProperty("Name", InstanceMemberBindingFlags, null, typeof(string), global::System.Array.Empty(), null)!.GetGetMethod(true)!))(obj); + private static global::System.Action? s_set_PrivateProps_Name; + private static void __set_PrivateProps_Name(global::TestApp.PrivateProps obj, string value) => (s_set_PrivateProps_Name ??= (global::System.Action)global::System.Delegate.CreateDelegate(typeof(global::System.Action), typeof(global::TestApp.PrivateProps).GetProperty("Name", InstanceMemberBindingFlags, null, typeof(string), global::System.Array.Empty(), null)!.GetSetMethod(true)!))(obj, value); + private static global::System.Func? s_get_PrivateProps_Age; + private static int __get_PrivateProps_Age(global::TestApp.PrivateProps obj) => (s_get_PrivateProps_Age ??= (global::System.Func)global::System.Delegate.CreateDelegate(typeof(global::System.Func), typeof(global::TestApp.PrivateProps).GetProperty("Age", InstanceMemberBindingFlags, null, typeof(int), global::System.Array.Empty(), null)!.GetGetMethod(true)!))(obj); + private static global::System.Action? s_set_PrivateProps_Age; + private static void __set_PrivateProps_Age(global::TestApp.PrivateProps obj, int value) => (s_set_PrivateProps_Age ??= (global::System.Action)global::System.Delegate.CreateDelegate(typeof(global::System.Action), typeof(global::TestApp.PrivateProps).GetProperty("Age", InstanceMemberBindingFlags, null, typeof(int), global::System.Array.Empty(), null)!.GetSetMethod(true)!))(obj, value); } } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/Baselines/UnsafeAccessors_PrivateProperties/net462/MyContext.PropertyNames.g.cs.txt b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/Baselines/UnsafeAccessors_PrivateProperties/net462/MyContext.PropertyNames.g.cs.txt index d66770f07f5bb9..db308685fcc80f 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/Baselines/UnsafeAccessors_PrivateProperties/net462/MyContext.PropertyNames.g.cs.txt +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/Baselines/UnsafeAccessors_PrivateProperties/net462/MyContext.PropertyNames.g.cs.txt @@ -10,5 +10,7 @@ namespace TestApp { internal partial class MyContext { + private static readonly global::System.Text.Json.JsonEncodedText PropName_Name = global::System.Text.Json.JsonEncodedText.Encode("Name"); + private static readonly global::System.Text.Json.JsonEncodedText PropName_Age = global::System.Text.Json.JsonEncodedText.Encode("Age"); } } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/Baselines/UnsafeAccessors_PrivateProperties/netcoreapp/MyContext.PrivateProps.g.cs.txt b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/Baselines/UnsafeAccessors_PrivateProperties/netcoreapp/MyContext.PrivateProps.g.cs.txt index 9cbe85129e4890..3e495ce1a8484c 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/Baselines/UnsafeAccessors_PrivateProperties/netcoreapp/MyContext.PrivateProps.g.cs.txt +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/Baselines/UnsafeAccessors_PrivateProperties/netcoreapp/MyContext.PrivateProps.g.cs.txt @@ -57,10 +57,10 @@ namespace TestApp IsVirtual = false, DeclaringType = typeof(global::TestApp.PrivateProps), Converter = null, - Getter = null, - Setter = null, + Getter = static obj => __get_PrivateProps_Name((global::TestApp.PrivateProps)obj), + Setter = static (obj, value) => __set_PrivateProps_Name((global::TestApp.PrivateProps)obj, value!), IgnoreCondition = null, - HasJsonInclude = false, + HasJsonInclude = true, IsExtensionData = false, NumberHandling = null, PropertyName = "Name", @@ -77,10 +77,10 @@ namespace TestApp IsVirtual = false, DeclaringType = typeof(global::TestApp.PrivateProps), Converter = null, - Getter = null, - Setter = null, + Getter = static obj => __get_PrivateProps_Age((global::TestApp.PrivateProps)obj), + Setter = static (obj, value) => __set_PrivateProps_Age((global::TestApp.PrivateProps)obj, value!), IgnoreCondition = null, - HasJsonInclude = false, + HasJsonInclude = true, IsExtensionData = false, NumberHandling = null, PropertyName = "Age", @@ -105,8 +105,19 @@ namespace TestApp writer.WriteStartObject(); + writer.WriteString(PropName_Name, __get_PrivateProps_Name(((global::TestApp.PrivateProps)value))); + writer.WriteNumber(PropName_Age, __get_PrivateProps_Age(((global::TestApp.PrivateProps)value))); writer.WriteEndObject(); } + + [global::System.Runtime.CompilerServices.UnsafeAccessorAttribute(global::System.Runtime.CompilerServices.UnsafeAccessorKind.Method, Name = "get_Name")] + private static extern string __get_PrivateProps_Name(global::TestApp.PrivateProps obj); + [global::System.Runtime.CompilerServices.UnsafeAccessorAttribute(global::System.Runtime.CompilerServices.UnsafeAccessorKind.Method, Name = "set_Name")] + private static extern void __set_PrivateProps_Name(global::TestApp.PrivateProps obj, string value); + [global::System.Runtime.CompilerServices.UnsafeAccessorAttribute(global::System.Runtime.CompilerServices.UnsafeAccessorKind.Method, Name = "get_Age")] + private static extern int __get_PrivateProps_Age(global::TestApp.PrivateProps obj); + [global::System.Runtime.CompilerServices.UnsafeAccessorAttribute(global::System.Runtime.CompilerServices.UnsafeAccessorKind.Method, Name = "set_Age")] + private static extern void __set_PrivateProps_Age(global::TestApp.PrivateProps obj, int value); } } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/Baselines/UnsafeAccessors_PrivateProperties/netcoreapp/MyContext.PropertyNames.g.cs.txt b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/Baselines/UnsafeAccessors_PrivateProperties/netcoreapp/MyContext.PropertyNames.g.cs.txt index d66770f07f5bb9..db308685fcc80f 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/Baselines/UnsafeAccessors_PrivateProperties/netcoreapp/MyContext.PropertyNames.g.cs.txt +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/Baselines/UnsafeAccessors_PrivateProperties/netcoreapp/MyContext.PropertyNames.g.cs.txt @@ -10,5 +10,7 @@ namespace TestApp { internal partial class MyContext { + private static readonly global::System.Text.Json.JsonEncodedText PropName_Name = global::System.Text.Json.JsonEncodedText.Encode("Name"); + private static readonly global::System.Text.Json.JsonEncodedText PropName_Age = global::System.Text.Json.JsonEncodedText.Encode("Age"); } } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorDiagnosticsTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorDiagnosticsTests.cs index 8dfd87b307bccb..6c53ae75f1410d 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorDiagnosticsTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorDiagnosticsTests.cs @@ -264,33 +264,10 @@ public void DoNotWarnOnClassesWithRequiredProperties() #endif [Fact] - public void WarnsOnClassesWithInaccessibleJsonIncludeProperties() + public void DoNotWarnOnClassesWithInaccessibleJsonIncludeProperties() { Compilation compilation = CompilationHelper.CreateCompilationWithInaccessibleJsonIncludeProperties(); - JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation, disableDiagnosticValidation: true); - - Location idLocation = compilation.GetSymbolsWithName("Id").First().Locations[0]; - Location address2Location = compilation.GetSymbolsWithName("Address2").First().Locations[0]; - Location countryLocation = compilation.GetSymbolsWithName("Country").First().Locations[0]; - Location privateFieldLocation = compilation.GetSymbolsWithName("privateField").First().Locations[0]; - Location protectedFieldLocation = compilation.GetSymbolsWithName("protectedField").First().Locations[0]; - Location protectedPropertyLocation = compilation.GetSymbolsWithName("ProtectedProperty").First().Locations[0]; - Location internalPropertyWithPrivateGetterLocation = compilation.GetSymbolsWithName("InternalPropertyWithPrivateGetter").First().Locations[0]; - Location internalPropertyWithPrivateSetterLocation = compilation.GetSymbolsWithName("InternalPropertyWithPrivateSetter").First().Locations[0]; - - var expectedDiagnostics = new DiagnosticData[] - { - new(DiagnosticSeverity.Warning, idLocation, "The member 'Location.Id' has been annotated with the JsonIncludeAttribute but is not visible to the source generator."), - new(DiagnosticSeverity.Warning, address2Location, "The member 'Location.Address2' has been annotated with the JsonIncludeAttribute but is not visible to the source generator."), - new(DiagnosticSeverity.Warning, countryLocation, "The member 'Location.Country' has been annotated with the JsonIncludeAttribute but is not visible to the source generator."), - new(DiagnosticSeverity.Warning, privateFieldLocation, "The member 'Location.privateField' has been annotated with the JsonIncludeAttribute but is not visible to the source generator."), - new(DiagnosticSeverity.Warning, protectedFieldLocation, "The member 'Location.protectedField' has been annotated with the JsonIncludeAttribute but is not visible to the source generator."), - new(DiagnosticSeverity.Warning, protectedPropertyLocation, "The member 'Location.ProtectedProperty' has been annotated with the JsonIncludeAttribute but is not visible to the source generator."), - new(DiagnosticSeverity.Warning, internalPropertyWithPrivateGetterLocation, "The member 'Location.InternalPropertyWithPrivateGetter' has been annotated with the JsonIncludeAttribute but is not visible to the source generator."), - new(DiagnosticSeverity.Warning, internalPropertyWithPrivateSetterLocation, "The member 'Location.InternalPropertyWithPrivateSetter' has been annotated with the JsonIncludeAttribute but is not visible to the source generator."), - }; - - CompilationHelper.AssertEqualDiagnosticMessages(expectedDiagnostics, result.Diagnostics); + CompilationHelper.RunJsonSourceGenerator(compilation); } [Fact] diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorOutputTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorOutputTests.cs index 95e14d4913d8ec..b59cc9a146fc64 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorOutputTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorOutputTests.cs @@ -273,7 +273,7 @@ public class PrivateProps private int Age { get; set; } } } - """, nameof(UnsafeAccessors_PrivateProperties), disableDiagnosticValidation: true); + """, nameof(UnsafeAccessors_PrivateProperties)); } [Fact] From f0132fe99169bb90152861438f395a1dd9a9f6aa Mon Sep 17 00:00:00 2001 From: Eirik Tsarpalis Date: Fri, 3 Jul 2026 13:44:12 +0300 Subject: [PATCH 2/3] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../Common/PropertyVisibilityTests.NonPublicAccessors.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libraries/System.Text.Json/tests/Common/PropertyVisibilityTests.NonPublicAccessors.cs b/src/libraries/System.Text.Json/tests/Common/PropertyVisibilityTests.NonPublicAccessors.cs index 31100ce277a3d7..d30a350116b09f 100644 --- a/src/libraries/System.Text.Json/tests/Common/PropertyVisibilityTests.NonPublicAccessors.cs +++ b/src/libraries/System.Text.Json/tests/Common/PropertyVisibilityTests.NonPublicAccessors.cs @@ -366,9 +366,7 @@ public virtual async Task NonPublicProperty_JsonInclude_WorksAsExpected([Dynamic string json = """{"MyString":"value"}"""; MemberInfo memberInfo = type.GetMember("MyString", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)[0]; - object result = await Serializer.DeserializeWrapper("""{"MyString":"value"}""", type); - Assert.IsType(type, result); - Assert.Equal(memberInfo is PropertyInfo p ? p.GetValue(result) : ((FieldInfo)memberInfo).GetValue(result), "value"); + Assert.Equal("value", memberInfo is PropertyInfo p ? p.GetValue(result) : ((FieldInfo)memberInfo).GetValue(result)); string actualJson = await Serializer.SerializeWrapper(result, type); Assert.Equal(json, actualJson); From fb752bb9a0f0fc61518027e1a726cab202c2a72e Mon Sep 17 00:00:00 2001 From: Eirik Tsarpalis Date: Fri, 3 Jul 2026 13:55:29 +0300 Subject: [PATCH 3/3] Fix test broken by autofix and use json variable in deserialize call The Copilot Autofix commit removed the DeserializeWrapper call and Assert.IsType assertion from NonPublicProperty_JsonInclude_WorksAsExpected while leaving references to the now-undeclared 'result' local, breaking compilation. Restore the deserialize call (using the existing 'json' variable per review feedback) and the type assertion. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../tests/Common/PropertyVisibilityTests.NonPublicAccessors.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libraries/System.Text.Json/tests/Common/PropertyVisibilityTests.NonPublicAccessors.cs b/src/libraries/System.Text.Json/tests/Common/PropertyVisibilityTests.NonPublicAccessors.cs index d30a350116b09f..0d56f8d2e00513 100644 --- a/src/libraries/System.Text.Json/tests/Common/PropertyVisibilityTests.NonPublicAccessors.cs +++ b/src/libraries/System.Text.Json/tests/Common/PropertyVisibilityTests.NonPublicAccessors.cs @@ -366,6 +366,8 @@ public virtual async Task NonPublicProperty_JsonInclude_WorksAsExpected([Dynamic string json = """{"MyString":"value"}"""; MemberInfo memberInfo = type.GetMember("MyString", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)[0]; + object result = await Serializer.DeserializeWrapper(json, type); + Assert.IsType(type, result); Assert.Equal("value", memberInfo is PropertyInfo p ? p.GetValue(result) : ((FieldInfo)memberInfo).GetValue(result)); string actualJson = await Serializer.SerializeWrapper(result, type);