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 00000000000000..faa8529cfd73b8
--- /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 14bfda6302bae7..131e08d0d0c2bf 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 @@ private string GenerateForTypeWithUnknownConverter(TypeGenerationSpec typeMetada
}}
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 @@ private string GenerateForTypeWithUnknownConverter(TypeGenerationSpec typeMetada
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 string GeneratePropMetadataInitFunc(TypeGenerationSpec typeGenerationSpe
? @$"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 string GenerateFastPathFuncForObject(TypeGenerationSpec typeGenSpec)
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 string GetFetchLogicForRuntimeSpecifiedCustomConverter()
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 string GetFetchLogicForGetCustomConverter_TypesWithFactories()
{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 63ab0e6579c180..9ba0372893c3fd 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 @@ private sealed class Parser
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 @@ private TypeGenerationSpec GetOrAddTypeGenerationSpec(Type type, JsonSourceGener
string? converterInstatiationLogic = null;
bool implementsIJsonOnSerialized = false;
bool implementsIJsonOnSerializing = false;
+ bool hasEncounteredInitOnlyProperties = false;
bool hasTypeFactoryConverter = false;
bool hasPropertyFactoryConverters = false;
@@ -954,6 +971,17 @@ void CacheMemberHelper()
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 @@ private PropertyGenerationSpec GetPropertyGenerationSpec(
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 @@ private PropertyGenerationSpec GetPropertyGenerationSpec(
RuntimePropertyName = runtimePropertyName,
PropertyNameVarName = propertyNameVarName,
IsReadOnly = isReadOnly,
+ IsInitOnlySetter = setterIsInitOnly,
CanUseGetter = canUseGetter,
CanUseSetter = canUseSetter,
GetterIsVirtual = getterIsVirtual,
@@ -1227,13 +1257,15 @@ private static void ProcessMember(
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 @@ private static void ProcessMember(
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 50400453971574..c9c4cbd3ddc516 100644
--- a/src/libraries/System.Text.Json/gen/PropertyGenerationSpec.cs
+++ b/src/libraries/System.Text.Json/gen/PropertyGenerationSpec.cs
@@ -16,6 +16,9 @@ internal sealed class PropertyGenerationSpec
///
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; }
@@ -39,6 +42,11 @@ internal sealed class PropertyGenerationSpec
///
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 389b14eae8452f..1074f0eb468179 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 710c988fa50f18..3b613f37f21660 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 e4c65b68fad573..80ee5a4c3927c9 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 e97f5789c1b0ae..383c9b6e1cd3ce 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 d4daa7c3a925d0..abf9fecd62cf1e 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 b72f65668d00f7..9edb25fc978211 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 17f511d22d9033..b3312d606a2dbd 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 1a458268c19213..1214ae9ffa70c2 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 e757ef48a993e4..257006c2b352e0 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 34765df4812c10..11492c23762969 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 bdac6af0cb198b..f1bb2a252c0438 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 e8eedfafa5f515..3d5e138aebe4cb 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 12bee676f0a449..a934f5c4d315f1 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 0f1c6dd91acdb5..4e236ab87e0030 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 0153870dfd59c8..97d78152396485 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 819f9529af2db9..02d51cdef6a48c 100644
--- a/src/libraries/System.Text.Json/gen/TypeGenerationSpec.cs
+++ b/src/libraries/System.Text.Json/gen/TypeGenerationSpec.cs
@@ -64,7 +64,7 @@ internal class TypeGenerationSpec
///
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 @@ public bool TryFilterSerializableProps(
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 @@ public bool TryFilterSerializableProps(
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 @@ public bool TryFilterSerializableProps(
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 0c8dc6a941c38f..af5159c0552e36 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 @@ public async Task HonorNamingPolicy()
}
[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 e3cc69ede77eb0..8b2243fd835c22 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 @@ public override async Task Honor_JsonSerializablePropertyAttribute_OnProperties(
""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 @@ public override async Task Honor_JsonSerializablePropertyAttribute_OnProperties(
[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 @@ public override async Task InitOnlyProperties(Type type)
[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 @@ public override async Task HonorCustomConverter_UsingPrivateSetter()
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 @@ public override async Task Public_And_NonPublicPropertyAccessors_PropertyAttribu
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 @@ public override async Task HonorJsonPropertyName()
[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 @@ public override async Task JsonIgnoreCondition_WhenWritingNull_OnValueType_Fail_
[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 cc608604518076..71681de2554820 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 @@
truetrue
- $(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 c9457cda3c135c..b84c518275ffc5 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 @@ public class Location
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 caa283f25f91a3..470c83408c2c18 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 static void Main()
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());
+ }
}
}