From: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 15 Sep 2021 22:03:50 +0000 (-0700) Subject: [release/6.0] Emit diagnostics & exceptions for sourcegen handling init-only properti... X-Git-Tag: accepted/tizen/unified/20220110.054933~133 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=0bc0c0ac28e74b5d107781a3caa456f9ef2be4bb;p=platform%2Fupstream%2Fdotnet%2Fruntime.git [release/6.0] Emit diagnostics & exceptions for sourcegen handling init-only properties & JsonInclude attributes (#59097) * Emit diagnostic warnings and exceptions when sourcegen is handling init-only inaccessible JsonInclude properties. * add localizations for runtime exception messages * remove exception messages from resource strings * fix alphabetical ordering Co-authored-by: Eirik Tsarpalis --- diff --git a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.ExceptionMessages.cs b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.ExceptionMessages.cs new file mode 100644 index 0000000..faa8529 --- /dev/null +++ b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.ExceptionMessages.cs @@ -0,0 +1,36 @@ +// 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.Text; + +namespace System.Text.Json.SourceGeneration +{ + public sealed partial class JsonSourceGenerator + { + private sealed partial class Emitter + { + /// + /// Unlike sourcegen warnings, exception messages should not be localized so we keep them in source. + /// + private static class ExceptionMessages + { + public const string InaccessibleJsonIncludePropertiesNotSupported = + "The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator."; + + public const string IncompatibleConverterType = + "The converter '{0}' is not compatible with the type '{1}'."; + + public const string InitOnlyPropertyDeserializationNotSupported = + "Deserialization of init-only properties is currently not supported in source generation mode."; + + public const string InvalidJsonConverterFactoryOutput = + "The converter '{0}' cannot return null or a JsonConverterFactory instance."; + + public const string InvalidSerializablePropertyConfiguration = + "Invalid serializable-property configuration specified for type '{0}'. For more information, see 'JsonSourceGenerationMode.Serialization'."; + }; + } + } +} diff --git a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs index 14bfda6..131e08d 100644 --- a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs +++ b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs @@ -324,7 +324,7 @@ namespace {@namespace} }} else {{ - throw new {InvalidOperationExceptionTypeRef}($""The converter '{{converter.GetType()}}' is not compatible with the type '{{typeToConvert}}'.""); + throw new {InvalidOperationExceptionTypeRef}(string.Format(""{ExceptionMessages.IncompatibleConverterType}"", converter.GetType(), typeToConvert)); }} }}"); } @@ -333,7 +333,7 @@ namespace {@namespace} metadataInitSource.Append($@" if (!converter.CanConvert(typeToConvert)) {{ - throw new {InvalidOperationExceptionTypeRef}($""The converter '{{converter.GetType()}}' is not compatible with the type '{{typeToConvert}}'.""); + throw new {InvalidOperationExceptionTypeRef}(string.Format(""{ExceptionMessages.IncompatibleConverterType}"", converter.GetType(), typeToConvert)); }}"); } @@ -711,25 +711,28 @@ private static {JsonPropertyInfoTypeRef}[] {propInitMethodName}({JsonSerializerC ? @$"jsonPropertyName: ""{memberMetadata.JsonPropertyName}""" : "jsonPropertyName: null"; - string getterNamedArg = memberMetadata.CanUseGetter && - memberMetadata.DefaultIgnoreCondition != JsonIgnoreCondition.Always - ? $"getter: static (obj) => (({declaringTypeCompilableName})obj).{clrPropertyName}" - : "getter: null"; - - string setterNamedArg; - if (memberMetadata.CanUseSetter && - memberMetadata.DefaultIgnoreCondition != JsonIgnoreCondition.Always) + string getterNamedArg = memberMetadata switch { - string propMutation = typeGenerationSpec.IsValueType - ? @$"{UnsafeTypeRef}.Unbox<{declaringTypeCompilableName}>(obj).{clrPropertyName} = value!" - : $@"(({declaringTypeCompilableName})obj).{clrPropertyName} = value!"; - - setterNamedArg = $"setter: static (obj, value) => {propMutation}"; - } - else + { DefaultIgnoreCondition: JsonIgnoreCondition.Always } => "getter: null", + { CanUseGetter: true } => $"getter: static (obj) => (({declaringTypeCompilableName})obj).{clrPropertyName}", + { CanUseGetter: false, HasJsonInclude: true } + => @$"getter: static (obj) => throw new {InvalidOperationExceptionTypeRef}(""{string.Format(ExceptionMessages.InaccessibleJsonIncludePropertiesNotSupported, typeGenerationSpec.Type.Name, memberMetadata.ClrName)}"")", + _ => "getter: null" + }; + + string setterNamedArg = memberMetadata switch { - setterNamedArg = "setter: null"; - } + { DefaultIgnoreCondition: JsonIgnoreCondition.Always } => "setter: null", + { CanUseSetter: true, IsInitOnlySetter: true } + => @$"setter: static (obj, value) => throw new {InvalidOperationExceptionTypeRef}(""{ExceptionMessages.InitOnlyPropertyDeserializationNotSupported}"")", + { CanUseSetter: true } when typeGenerationSpec.IsValueType + => $@"setter: static (obj, value) => {UnsafeTypeRef}.Unbox<{declaringTypeCompilableName}>(obj).{clrPropertyName} = value!", + { CanUseSetter: true } + => @$"setter: static (obj, value) => (({declaringTypeCompilableName})obj).{clrPropertyName} = value!", + { CanUseSetter: false, HasJsonInclude: true } + => @$"setter: static (obj, value) => throw new {InvalidOperationExceptionTypeRef}(""{string.Format(ExceptionMessages.InaccessibleJsonIncludePropertiesNotSupported, typeGenerationSpec.Type.Name, memberMetadata.ClrName)}"")", + _ => "setter: null", + }; JsonIgnoreCondition? ignoreCondition = memberMetadata.DefaultIgnoreCondition; string ignoreConditionNamedArg = ignoreCondition.HasValue @@ -821,12 +824,12 @@ private static {JsonParameterInfoValuesTypeRef}[] {typeGenerationSpec.TypeInfoPr out Dictionary? serializableProperties, out bool castingRequiredForProps)) { - string exceptionMessage = @$"""Invalid serializable-property configuration specified for type '{typeRef}'. For more information, see 'JsonSourceGenerationMode.Serialization'."""; + string exceptionMessage = string.Format(ExceptionMessages.InvalidSerializablePropertyConfiguration, typeRef); return GenerateFastPathFuncForType( serializeMethodName, typeRef, - $@"throw new {InvalidOperationExceptionTypeRef}({exceptionMessage});", + $@"throw new {InvalidOperationExceptionTypeRef}(""{exceptionMessage}"");", canBeNull: false); // Skip null check since we want to throw an exception straightaway. } @@ -1202,7 +1205,7 @@ private static {JsonSerializerOptionsTypeRef} {DefaultOptionsStaticVarName} {{ g converter = factory.CreateConverter(type, {OptionsInstanceVariableName}); if (converter == null || converter is {JsonConverterFactoryTypeRef}) {{ - throw new {InvalidOperationExceptionTypeRef}($""The converter '{{factory.GetType()}}' cannot return null or a JsonConverterFactory instance.""); + throw new {InvalidOperationExceptionTypeRef}(string.Format(""{ExceptionMessages.InvalidJsonConverterFactoryOutput}"", factory.GetType())); }} }} @@ -1233,7 +1236,7 @@ private {JsonConverterTypeRef} {GetConverterFromFactoryMethodName}({TypeTypeRef} {JsonConverterTypeRef}? converter = factory.CreateConverter(type, {Emitter.OptionsInstanceVariableName}); if (converter == null || converter is {JsonConverterFactoryTypeRef}) {{ - throw new {InvalidOperationExceptionTypeRef}($""The converter '{{factory.GetType()}}' cannot return null or a JsonConverterFactory instance.""); + throw new {InvalidOperationExceptionTypeRef}(string.Format(""{ExceptionMessages.InvalidJsonConverterFactoryOutput}"", factory.GetType())); }} return converter; diff --git a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs index 63ab0e6..9ba0372 100644 --- a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs +++ b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs @@ -139,6 +139,22 @@ namespace System.Text.Json.SourceGeneration defaultSeverity: DiagnosticSeverity.Error, isEnabledByDefault: true); + private static DiagnosticDescriptor InitOnlyPropertyDeserializationNotSupported { get; } = new DiagnosticDescriptor( + id: "SYSLIB1037", + title: new LocalizableResourceString(nameof(SR.InitOnlyPropertyDeserializationNotSupportedTitle), SR.ResourceManager, typeof(FxResources.System.Text.Json.SourceGeneration.SR)), + messageFormat: new LocalizableResourceString(nameof(SR.InitOnlyPropertyDeserializationNotSupportedFormat), SR.ResourceManager, typeof(FxResources.System.Text.Json.SourceGeneration.SR)), + category: JsonConstants.SystemTextJsonSourceGenerationName, + defaultSeverity: DiagnosticSeverity.Warning, + isEnabledByDefault: true); + + private static DiagnosticDescriptor InaccessibleJsonIncludePropertiesNotSupported { get; } = new DiagnosticDescriptor( + 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 Parser(Compilation compilation, in JsonSourceGenerationContext sourceGenerationContext) { _compilation = compilation; @@ -624,6 +640,7 @@ namespace System.Text.Json.SourceGeneration string? converterInstatiationLogic = null; bool implementsIJsonOnSerialized = false; bool implementsIJsonOnSerializing = false; + bool hasEncounteredInitOnlyProperties = false; bool hasTypeFactoryConverter = false; bool hasPropertyFactoryConverters = false; @@ -954,6 +971,17 @@ namespace System.Text.Json.SourceGeneration dataExtensionPropGenSpec = GetOrAddTypeGenerationSpec(propType, generationMode); _implicitlyRegisteredTypes.Add(dataExtensionPropGenSpec); } + + if (!hasEncounteredInitOnlyProperties && spec.CanUseSetter && spec.IsInitOnlySetter) + { + _sourceGenerationContext.ReportDiagnostic(Diagnostic.Create(InitOnlyPropertyDeserializationNotSupported, Location.None, new string[] { type.Name })); + hasEncounteredInitOnlyProperties = true; + } + + if (spec.HasJsonInclude && (!spec.CanUseGetter || !spec.CanUseSetter || !spec.IsPublic)) + { + _sourceGenerationContext.ReportDiagnostic(Diagnostic.Create(InaccessibleJsonIncludePropertiesNotSupported, Location.None, new string[] { type.Name, spec.ClrName })); + } } } @@ -1079,7 +1107,8 @@ namespace System.Text.Json.SourceGeneration out bool canUseGetter, out bool canUseSetter, out bool getterIsVirtual, - out bool setterIsVirtual); + out bool setterIsVirtual, + out bool setterIsInitOnly); string clrName = memberInfo.Name; string runtimePropertyName = DetermineRuntimePropName(clrName, jsonPropertyName, _currentContextNamingPolicy); @@ -1095,6 +1124,7 @@ namespace System.Text.Json.SourceGeneration RuntimePropertyName = runtimePropertyName, PropertyNameVarName = propertyNameVarName, IsReadOnly = isReadOnly, + IsInitOnlySetter = setterIsInitOnly, CanUseGetter = canUseGetter, CanUseSetter = canUseSetter, GetterIsVirtual = getterIsVirtual, @@ -1227,13 +1257,15 @@ namespace System.Text.Json.SourceGeneration out bool canUseGetter, out bool canUseSetter, out bool getterIsVirtual, - out bool setterIsVirtual) + out bool setterIsVirtual, + out bool setterIsInitOnly) { isPublic = false; canUseGetter = false; canUseSetter = false; getterIsVirtual = false; setterIsVirtual = false; + setterIsInitOnly = false; switch (memberInfo) { @@ -1260,15 +1292,16 @@ namespace System.Text.Json.SourceGeneration if (setMethod != null) { isReadOnly = false; + setterIsInitOnly = setMethod.IsInitOnly(); if (setMethod.IsPublic) { isPublic = true; - canUseSetter = !setMethod.IsInitOnly(); + canUseSetter = true; } else if (setMethod.IsAssembly) { - canUseSetter = hasJsonInclude && !setMethod.IsInitOnly(); + canUseSetter = hasJsonInclude; } setterIsVirtual = setMethod.IsVirtual; diff --git a/src/libraries/System.Text.Json/gen/PropertyGenerationSpec.cs b/src/libraries/System.Text.Json/gen/PropertyGenerationSpec.cs index 5040045..c9c4cbd 100644 --- a/src/libraries/System.Text.Json/gen/PropertyGenerationSpec.cs +++ b/src/libraries/System.Text.Json/gen/PropertyGenerationSpec.cs @@ -16,6 +16,9 @@ namespace System.Text.Json.SourceGeneration /// public bool IsProperty { get; init; } + /// + /// If representing a property, returns true if either the getter or setter are public. + /// public bool IsPublic { get; init; } public bool IsVirtual { get; init; } @@ -40,6 +43,11 @@ namespace System.Text.Json.SourceGeneration public bool IsReadOnly { get; init; } /// + /// Whether the property has an init-only set method. + /// + public bool IsInitOnlySetter { get; init; } + + /// /// Whether the property has a public or internal (only usable when JsonIncludeAttribute is specified) /// getter that can be referenced in generated source code. /// diff --git a/src/libraries/System.Text.Json/gen/Resources/Strings.resx b/src/libraries/System.Text.Json/gen/Resources/Strings.resx index 389b14e..1074f0e 100644 --- a/src/libraries/System.Text.Json/gen/Resources/Strings.resx +++ b/src/libraries/System.Text.Json/gen/Resources/Strings.resx @@ -153,4 +153,16 @@ Data extension property type invalid. - \ No newline at end of file + + Deserialization of init-only properties is currently not supported in source generation mode. + + + The type '{0}' defines init-only properties, deserialization of which is currently not supported in source generation mode. + + + 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. + + 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 710c988..3b613f3 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 @@ -32,6 +32,26 @@ Duplicitní název typu + + The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. + The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. + + + + Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. + Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. + + + + The type '{0}' defines init-only properties, deserialization of which is currently not supported in source generation mode. + The type '{0}' defines init-only properties, deserialization of which is currently not supported in source generation mode. + + + + Deserialization of init-only properties is currently not supported in source generation mode. + Deserialization of init-only properties is currently not supported in source generation mode. + + Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'. Typ {0} má více konstruktorů anotovaných s JsonConstructorAttribute. 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 e4c65b6..80ee5a4 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 @@ -32,6 +32,26 @@ Doppelter Typname + + The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. + The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. + + + + Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. + Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. + + + + The type '{0}' defines init-only properties, deserialization of which is currently not supported in source generation mode. + The type '{0}' defines init-only properties, deserialization of which is currently not supported in source generation mode. + + + + Deserialization of init-only properties is currently not supported in source generation mode. + Deserialization of init-only properties is currently not supported in source generation mode. + + Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'. Typ "{0}" weist mehrere Konstruktoren mit dem Kommentar "JsonConstructorAttribute" auf. 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 e97f578..383c9b6 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 @@ -32,6 +32,26 @@ Nombre de tipo duplicado. + + The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. + The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. + + + + Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. + Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. + + + + The type '{0}' defines init-only properties, deserialization of which is currently not supported in source generation mode. + The type '{0}' defines init-only properties, deserialization of which is currently not supported in source generation mode. + + + + Deserialization of init-only properties is currently not supported in source generation mode. + Deserialization of init-only properties is currently not supported in source generation mode. + + Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'. El tipo '{0}' tiene varios constructores anotados con 'JsonConstructorAttribute'. 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 d4daa7c..abf9fec 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 @@ -32,6 +32,26 @@ Nom de type dupliqué. + + The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. + The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. + + + + Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. + Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. + + + + The type '{0}' defines init-only properties, deserialization of which is currently not supported in source generation mode. + The type '{0}' defines init-only properties, deserialization of which is currently not supported in source generation mode. + + + + Deserialization of init-only properties is currently not supported in source generation mode. + Deserialization of init-only properties is currently not supported in source generation mode. + + Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'. Le type' {0} 'a plusieurs constructeurs annotés avec’JsonConstructorAttribute'. 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 b72f656..9edb25f 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 @@ -32,6 +32,26 @@ Nome di tipo duplicato. + + The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. + The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. + + + + Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. + Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. + + + + The type '{0}' defines init-only properties, deserialization of which is currently not supported in source generation mode. + The type '{0}' defines init-only properties, deserialization of which is currently not supported in source generation mode. + + + + Deserialization of init-only properties is currently not supported in source generation mode. + Deserialization of init-only properties is currently not supported in source generation mode. + + Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'. Il tipo '{0}' contiene più costruttori che presentano l'annotazione 'JsonConstructorAttribute'. 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 17f511d..b3312d6 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 @@ -32,6 +32,26 @@ 重複した種類名。 + + The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. + The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. + + + + Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. + Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. + + + + The type '{0}' defines init-only properties, deserialization of which is currently not supported in source generation mode. + The type '{0}' defines init-only properties, deserialization of which is currently not supported in source generation mode. + + + + Deserialization of init-only properties is currently not supported in source generation mode. + Deserialization of init-only properties is currently not supported in source generation mode. + + Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'. 型 '{0}' には、'JsonConstructorAttribute' で注釈が付けられた複数のコンストラクターがあります。 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 1a45826..1214ae9 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 @@ -32,6 +32,26 @@ 중복된 형식 이름입니다. + + The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. + The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. + + + + Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. + Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. + + + + The type '{0}' defines init-only properties, deserialization of which is currently not supported in source generation mode. + The type '{0}' defines init-only properties, deserialization of which is currently not supported in source generation mode. + + + + Deserialization of init-only properties is currently not supported in source generation mode. + Deserialization of init-only properties is currently not supported in source generation mode. + + Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'. '{0}' 형식에 'JsonConstructorAttribute'로 주석이 추가된 여러 생성자가 있습니다. 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 e757ef4..257006c 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 @@ -32,6 +32,26 @@ Zduplikowana nazwa typu. + + The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. + The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. + + + + Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. + Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. + + + + The type '{0}' defines init-only properties, deserialization of which is currently not supported in source generation mode. + The type '{0}' defines init-only properties, deserialization of which is currently not supported in source generation mode. + + + + Deserialization of init-only properties is currently not supported in source generation mode. + Deserialization of init-only properties is currently not supported in source generation mode. + + Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'. Typ "{0}" ma wiele konstruktorów z adnotacją "JsonConstructorAttribute". 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 34765df..11492c2 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 @@ -32,6 +32,26 @@ Nome de tipo duplicado. + + The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. + The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. + + + + Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. + Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. + + + + The type '{0}' defines init-only properties, deserialization of which is currently not supported in source generation mode. + The type '{0}' defines init-only properties, deserialization of which is currently not supported in source generation mode. + + + + Deserialization of init-only properties is currently not supported in source generation mode. + Deserialization of init-only properties is currently not supported in source generation mode. + + Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'. O tipo '{0}' tem vários construtores anotados com 'JsonConstructorAttribute'. 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 bdac6af..f1bb2a2 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 @@ -32,6 +32,26 @@ Дублирующееся имя типа. + + The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. + The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. + + + + Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. + Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. + + + + The type '{0}' defines init-only properties, deserialization of which is currently not supported in source generation mode. + The type '{0}' defines init-only properties, deserialization of which is currently not supported in source generation mode. + + + + Deserialization of init-only properties is currently not supported in source generation mode. + Deserialization of init-only properties is currently not supported in source generation mode. + + Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'. Тип "{0}" имеет несколько конструкторов, аннотированных с использованием JsonConstructorAttribute. 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 e8eedfa..3d5e138 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 @@ -32,6 +32,26 @@ Yinelenen tür adı. + + The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. + The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. + + + + Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. + Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. + + + + The type '{0}' defines init-only properties, deserialization of which is currently not supported in source generation mode. + The type '{0}' defines init-only properties, deserialization of which is currently not supported in source generation mode. + + + + Deserialization of init-only properties is currently not supported in source generation mode. + Deserialization of init-only properties is currently not supported in source generation mode. + + Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'. '{0}' türünün 'JsonConstructorAttribute' ile açıklanan birden çok oluşturucusu var. 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 12bee67..a934f5c 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 @@ -32,6 +32,26 @@ 重复的类型名称。 + + The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. + The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. + + + + Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. + Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. + + + + The type '{0}' defines init-only properties, deserialization of which is currently not supported in source generation mode. + The type '{0}' defines init-only properties, deserialization of which is currently not supported in source generation mode. + + + + Deserialization of init-only properties is currently not supported in source generation mode. + Deserialization of init-only properties is currently not supported in source generation mode. + + Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'. 类型“{0}”具有用 “JsonConstructorAttribute” 批注的多个构造函数。 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 0f1c6dd..4e236ab 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 @@ -32,6 +32,26 @@ 重複類型名稱。 + + The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. + The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. + + + + Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. + Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode. + + + + The type '{0}' defines init-only properties, deserialization of which is currently not supported in source generation mode. + The type '{0}' defines init-only properties, deserialization of which is currently not supported in source generation mode. + + + + Deserialization of init-only properties is currently not supported in source generation mode. + Deserialization of init-only properties is currently not supported in source generation mode. + + Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'. 類型 '{0}' 包含多個以 'JsonConstructorAttribute' 註解的建構函式。 diff --git a/src/libraries/System.Text.Json/gen/System.Text.Json.SourceGeneration.targets b/src/libraries/System.Text.Json/gen/System.Text.Json.SourceGeneration.targets index 0153870..97d7815 100644 --- a/src/libraries/System.Text.Json/gen/System.Text.Json.SourceGeneration.targets +++ b/src/libraries/System.Text.Json/gen/System.Text.Json.SourceGeneration.targets @@ -1,4 +1,4 @@ - + netstandard2.0 $(MSBuildThisFileName) @@ -43,6 +43,7 @@ + diff --git a/src/libraries/System.Text.Json/gen/TypeGenerationSpec.cs b/src/libraries/System.Text.Json/gen/TypeGenerationSpec.cs index 819f952..02d51cd 100644 --- a/src/libraries/System.Text.Json/gen/TypeGenerationSpec.cs +++ b/src/libraries/System.Text.Json/gen/TypeGenerationSpec.cs @@ -64,7 +64,7 @@ namespace System.Text.Json.SourceGeneration /// public string? RuntimeTypeRef { get; private set; } - public TypeGenerationSpec? ExtensionDataPropertyTypeSpec { get; private set; } + public TypeGenerationSpec? ExtensionDataPropertyTypeSpec { get; private set; } public string? ConverterInstantiationLogic { get; private set; } @@ -160,7 +160,6 @@ namespace System.Text.Json.SourceGeneration for (int i = 0; i < PropertyGenSpecList.Count; i++) { PropertyGenerationSpec propGenSpec = PropertyGenSpecList[i]; - bool hasJsonInclude = propGenSpec.HasJsonInclude; JsonIgnoreCondition? ignoreCondition = propGenSpec.DefaultIgnoreCondition; if (ignoreCondition == JsonIgnoreCondition.WhenWritingNull && !propGenSpec.TypeGenerationSpec.CanBeNull) @@ -168,17 +167,21 @@ namespace System.Text.Json.SourceGeneration goto ReturnFalse; } - if (!propGenSpec.IsPublic) + // In case of JsonInclude fail if either: + // 1. the getter is not accessible by the source generator or + // 2. neither getter or setter methods are public. + if (propGenSpec.HasJsonInclude && (!propGenSpec.CanUseGetter || !propGenSpec.IsPublic)) { - if (hasJsonInclude) - { - goto ReturnFalse; - } + goto ReturnFalse; + } + // Discard any getters not accessible by the source generator. + if (!propGenSpec.CanUseGetter) + { continue; } - if (!propGenSpec.IsProperty && !hasJsonInclude && !options.IncludeFields) + if (!propGenSpec.IsProperty && !propGenSpec.HasJsonInclude && !options.IncludeFields) { continue; } @@ -223,7 +226,7 @@ namespace System.Text.Json.SourceGeneration castingRequiredForProps = PropertyGenSpecList.Count > serializableProperties.Count; return true; -ReturnFalse: + ReturnFalse: serializableProperties = null; castingRequiredForProps = false; return false; 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 0c8dc6a..af5159c 100644 --- a/src/libraries/System.Text.Json/tests/Common/PropertyVisibilityTests.NonPublicAccessors.cs +++ b/src/libraries/System.Text.Json/tests/Common/PropertyVisibilityTests.NonPublicAccessors.cs @@ -216,31 +216,46 @@ namespace System.Text.Json.Serialization.Tests } [Fact] - public virtual async Task HonorJsonPropertyName() + public virtual async Task HonorJsonPropertyName_PrivateGetter() { - string json = @"{""prop1"":1,""prop2"":2}"; + string json = @"{""prop1"":1}"; - var obj = await JsonSerializerWrapperForString.DeserializeWrapper(json); - Assert.Equal(MySmallEnum.AnotherValue, obj.GetMyEnum); - Assert.Equal(2, obj.MyInt); + var obj = await JsonSerializerWrapperForString.DeserializeWrapper(json); + Assert.Equal(MySmallEnum.AnotherValue, obj.GetProxy()); json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Contains(@"""prop1"":1", json); + } + + [Fact] + public virtual async Task HonorJsonPropertyName_PrivateSetter() + { + string json = @"{""prop2"":2}"; + + var obj = await JsonSerializerWrapperForString.DeserializeWrapper(json); + Assert.Equal(2, obj.MyInt); + + json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Contains(@"""prop2"":2", json); } - public struct StructWithPropertiesWithJsonPropertyName + public struct StructWithPropertiesWithJsonPropertyName_PrivateGetter { [JsonInclude] [JsonPropertyName("prop1")] public MySmallEnum MyEnum { private get; set; } + // For test validation. + internal MySmallEnum GetProxy() => MyEnum; + } + + public struct StructWithPropertiesWithJsonPropertyName_PrivateSetter + { [JsonInclude] [JsonPropertyName("prop2")] public int MyInt { get; private set; } - // For test validation. - internal MySmallEnum GetMyEnum => MyEnum; + internal void SetProxy(int myInt) => MyInt = myInt; } [Fact] 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 e3cc69e..8b2243f 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 @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.Reflection; using System.Text.Json.Serialization; using System.Text.Json.Serialization.Tests; using System.Threading.Tasks; @@ -46,17 +47,10 @@ namespace System.Text.Json.SourceGeneration.Tests ""MyUri"":""https://microsoft.com"" }"; - var obj = await JsonSerializerWrapperForString.DeserializeWrapper(json); - Assert.Equal(0, obj.MyInt); // Source gen can't use private setter - Assert.Equal("Hello", obj.MyString); - Assert.Equal(2f, obj.GetMyFloat); - Assert.Equal(new Uri("https://microsoft.com"), obj.MyUri); - - json = await JsonSerializerWrapperForString.SerializeWrapper(obj); - Assert.Contains(@"""MyInt"":0", json); - Assert.Contains(@"""MyString"":""Hello""", json); - Assert.DoesNotContain(@"""MyFloat"":", json); // Source gen can't use private setter - Assert.Contains(@"""MyUri"":""https://microsoft.com""", json); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(json)); + + var obj = new MyClass_WithNonPublicAccessors_WithPropertyAttributes(); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.SerializeWrapper(obj)); } [Theory] @@ -64,12 +58,15 @@ namespace System.Text.Json.SourceGeneration.Tests [InlineData(typeof(StructWithInitOnlyProperty))] public override async Task InitOnlyProperties(Type type) { - // Init-only setters cannot be referenced as get/set helpers in generated code. - object obj = await JsonSerializerWrapperForString.DeserializeWrapper(@"{""MyInt"":1}", type); - Assert.Equal(0, (int)type.GetProperty("MyInt").GetValue(obj)); + PropertyInfo property = type.GetProperty("MyInt"); // Init-only properties can be serialized. - Assert.Equal(@"{""MyInt"":0}", await JsonSerializerWrapperForString.SerializeWrapper(obj, type)); + object obj = Activator.CreateInstance(type); + property.SetValue(obj, 1); + Assert.Equal(@"{""MyInt"":1}", await JsonSerializerWrapperForString.SerializeWrapper(obj, type)); + + // Deserializing init-only properties is not supported. + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(@"{""MyInt"":1}", type)); } [Theory] @@ -78,12 +75,15 @@ namespace System.Text.Json.SourceGeneration.Tests [InlineData(typeof(Class_PropertyWith_ProtectedInitOnlySetter_WithAttribute))] public override async Task NonPublicInitOnlySetter_With_JsonInclude(Type type) { - // Init-only setters cannot be referenced as get/set helpers in generated code. - object obj = await JsonSerializerWrapperForString.DeserializeWrapper(@"{""MyInt"":1}", type); - Assert.Equal(0, (int)type.GetProperty("MyInt").GetValue(obj)); + PropertyInfo property = type.GetProperty("MyInt"); // Init-only properties can be serialized. - Assert.Equal(@"{""MyInt"":0}", await JsonSerializerWrapperForString.SerializeWrapper(obj, type)); + object obj = Activator.CreateInstance(type); + property.SetValue(obj, 1); + Assert.Equal(@"{""MyInt"":1}", await JsonSerializerWrapperForString.SerializeWrapper(obj, type)); + + // Deserializing init-only properties is not supported. + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(@"{""MyInt"":1}", type)); } [Fact] @@ -94,15 +94,15 @@ namespace System.Text.Json.SourceGeneration.Tests string json = @"{""MyEnum"":""AnotherValue"",""MyInt"":2}"; - // Deserialization baseline, without enum converter, we get JsonException. + // Deserialization baseline, without enum converter, we get JsonException. NB order of members in deserialized type is significant for this assertion to succeed. await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(json)); - var obj = await JsonSerializerWrapperForString.DeserializeWrapper(json, options); - Assert.Equal(MySmallEnum.AnotherValue, obj.GetMyEnum); - Assert.Equal(0, obj.MyInt); // Private setter can't be used with source-gen. + // JsonInclude not supported in source gen. + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(json, options)); - // ConverterForInt32 throws this exception. - await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.SerializeWrapper(obj, options)); + // JsonInclude on private getters not supported. + var obj = new StructWithPropertiesWithConverter(); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.SerializeWrapper(obj, options)); } [Fact] @@ -116,25 +116,32 @@ namespace System.Text.Json.SourceGeneration.Tests Assert.Equal(3, obj.Y); Assert.Equal(4, obj.GetZ); - json = await JsonSerializerWrapperForString.SerializeWrapper(obj); - Assert.Contains(@"""W"":1", json); - Assert.Contains(@"""X"":2", json); - Assert.Contains(@"""Y"":3", json); - Assert.DoesNotContain(@"""Z"":", json); // Private setter cannot be used with source gen. + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.SerializeWrapper(obj)); + } + + [Fact] + public override async Task HonorJsonPropertyName_PrivateGetter() + { + string json = @"{""prop1"":1}"; + + var obj = await JsonSerializerWrapperForString.DeserializeWrapper(json); + Assert.Equal(MySmallEnum.AnotherValue, obj.GetProxy()); + + // JsonInclude for private members not supported in source gen + await Assert.ThrowsAsync(async() => await JsonSerializerWrapperForString.SerializeWrapper(obj)); } [Fact] - public override async Task HonorJsonPropertyName() + public override async Task HonorJsonPropertyName_PrivateSetter() { - string json = @"{""prop1"":1,""prop2"":2}"; + string json = @"{""prop2"":2}"; - var obj = await JsonSerializerWrapperForString.DeserializeWrapper(json); - Assert.Equal(MySmallEnum.AnotherValue, obj.GetMyEnum); - Assert.Equal(0, obj.MyInt); // Private setter cannot be used with source gen. + // JsonInclude for private members not supported in source gen + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(json)); - json = await JsonSerializerWrapperForString.SerializeWrapper(obj); - Assert.DoesNotContain(@"""prop1"":", json); // Private getter cannot be used with source gen. - Assert.Contains(@"""prop2"":0", json); + var obj = new StructWithPropertiesWithJsonPropertyName_PrivateSetter(); + obj.SetProxy(2); + Assert.Equal(json, await JsonSerializerWrapperForString.SerializeWrapper(obj)); } [JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Metadata)] @@ -252,7 +259,8 @@ namespace System.Text.Json.SourceGeneration.Tests [JsonSerializable(typeof(ClassTwiceInheritedWithPropertyPolicyConflictWhichThrows))] [JsonSerializable(typeof(MyClass_WithNonPublicAccessors))] [JsonSerializable(typeof(ClassWithThingsToIgnore_PerProperty))] - [JsonSerializable(typeof(StructWithPropertiesWithJsonPropertyName))] + [JsonSerializable(typeof(StructWithPropertiesWithJsonPropertyName_PrivateGetter))] + [JsonSerializable(typeof(StructWithPropertiesWithJsonPropertyName_PrivateSetter))] [JsonSerializable(typeof(ClassWithValueAndReferenceTypes))] [JsonSerializable(typeof(ClassWithReadOnlyStringProperty_IgnoreWhenWritingDefault))] internal sealed partial class PropertyVisibilityTestsContext_Metadata : JsonSerializerContext @@ -417,7 +425,8 @@ namespace System.Text.Json.SourceGeneration.Tests [JsonSerializable(typeof(ClassTwiceInheritedWithPropertyPolicyConflictWhichThrows))] [JsonSerializable(typeof(MyClass_WithNonPublicAccessors))] [JsonSerializable(typeof(ClassWithThingsToIgnore_PerProperty))] - [JsonSerializable(typeof(StructWithPropertiesWithJsonPropertyName))] + [JsonSerializable(typeof(StructWithPropertiesWithJsonPropertyName_PrivateGetter))] + [JsonSerializable(typeof(StructWithPropertiesWithJsonPropertyName_PrivateSetter))] [JsonSerializable(typeof(ClassWithValueAndReferenceTypes))] [JsonSerializable(typeof(ClassWithReadOnlyStringProperty_IgnoreWhenWritingDefault))] internal sealed partial class PropertyVisibilityTestsContext_Default : JsonSerializerContext 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 cc60860..71681de 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 @@ -4,7 +4,9 @@ true true - $(NoWarn);SYSLIB0020 + + + $(NoWarn);SYSLIB0020;SYSLIB1037;SYSLIB1038 diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/CompilationHelper.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/CompilationHelper.cs index c9457cd..b84c518 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/CompilationHelper.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/CompilationHelper.cs @@ -275,11 +275,72 @@ namespace System.Text.Json.SourceGeneration.UnitTests return CreateCompilation(source); } + public static Compilation CreateCompilationWithInitOnlyProperties() + { + string source = @" + using System; + using System.Text.Json.Serialization; + + namespace HelloWorld + { + public class Location + { + public int Id { get; init; } + public string Address1 { get; init; } + public string Address2 { get; init; } + public string City { get; init; } + public string State { get; init; } + public string PostalCode { get; init; } + public string Name { get; init; } + public string PhoneNumber { get; init; } + public string Country { get; init; } + } + + [JsonSerializable(typeof(Location))] + public partial class MyJsonContext : JsonSerializerContext + { + } + }"; + + return CreateCompilation(source); + } + + public static Compilation CreateCompilationWithInaccessibleJsonIncludeProperties() + { + string source = @" + using System; + using System.Text.Json.Serialization; + + namespace HelloWorld + { + public class Location + { + [JsonInclude] + public int Id { get; private set; } + [JsonInclude] + public string Address1 { get; internal set; } + [JsonInclude] + private string Address2 { get; set; } + [JsonInclude] + public string PhoneNumber { internal get; set; } + [JsonInclude] + public string Country { private get; set; } + } + + [JsonSerializable(typeof(Location))] + public partial class MyJsonContext : JsonSerializerContext + { + } + }"; + + return CreateCompilation(source); + } + internal static void CheckDiagnosticMessages(ImmutableArray diagnostics, DiagnosticSeverity level, string[] expectedMessages) { string[] actualMessages = diagnostics.Where(diagnostic => diagnostic.Severity == level).Select(diagnostic => diagnostic.GetMessage()).ToArray(); - // Can't depending on reflection order when generating type metadata. + // Can't depend on reflection order when generating type metadata. Array.Sort(actualMessages); Array.Sort(expectedMessages); 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 caa283f..470c834 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 @@ -190,5 +190,38 @@ public class Program CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Warning, Array.Empty()); CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Error, Array.Empty()); } + + [Fact] + public void WarnOnClassesWithInitOnlyProperties() + { + Compilation compilation = CompilationHelper.CreateCompilationWithInitOnlyProperties(); + JsonSourceGenerator generator = new JsonSourceGenerator(); + CompilationHelper.RunGenerators(compilation, out var generatorDiags, generator); + + string[] expectedWarningDiagnostics = new string[] { "The type 'Location' defines init-only properties, deserialization of which is currently not supported in source generation mode." }; + + CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Info, Array.Empty()); + CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Warning, expectedWarningDiagnostics); + CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Error, Array.Empty()); + } + + [Fact] + public void WarnOnClassesWithInaccessibleJsonIncludeProperties() + { + Compilation compilation = CompilationHelper.CreateCompilationWithInaccessibleJsonIncludeProperties(); + JsonSourceGenerator generator = new JsonSourceGenerator(); + CompilationHelper.RunGenerators(compilation, out var generatorDiags, generator); + + string[] expectedWarningDiagnostics = new string[] + { + "The member 'Location.Id' has been annotated with the JsonIncludeAttribute but is not visible to the source generator.", + "The member 'Location.Address2' has been annotated with the JsonIncludeAttribute but is not visible to the source generator.", + "The member 'Location.Country' has been annotated with the JsonIncludeAttribute but is not visible to the source generator." + }; + + CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Info, Array.Empty()); + CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Warning, expectedWarningDiagnostics); + CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Error, Array.Empty()); + } } }