* Relax JsonIncludeAttribute to also support private or internal members.
* Relax JsonConstructorAttribute to include internal or private constructors (where applicable).
| __`SYSLIB1219`__ | *_`SYSLIB1214`-`SYSLIB1219` reserved for Microsoft.Extensions.Options.SourceGeneration.* |
| __`SYSLIB1220`__ | JsonSourceGenerator encountered a [JsonConverterAttribute] with an invalid type argument. |
| __`SYSLIB1221`__ | JsonSourceGenerator does not support this C# language version. |
-| __`SYSLIB1222`__ | *`SYSLIB1220`-`SYSLIB229` reserved for System.Text.Json.SourceGeneration.* |
+| __`SYSLIB1222`__ | Constructor annotated with JsonConstructorAttribute is inaccessible. |
| __`SYSLIB1223`__ | *`SYSLIB1220`-`SYSLIB229` reserved for System.Text.Json.SourceGeneration.* |
| __`SYSLIB1224`__ | *`SYSLIB1220`-`SYSLIB229` reserved for System.Text.Json.SourceGeneration.* |
| __`SYSLIB1225`__ | *`SYSLIB1220`-`SYSLIB229` reserved for System.Text.Json.SourceGeneration.* |
}
}
- // For correctness, throw if multiple ctors have [JsonConstructor], even if one or more are non-public.
- ConstructorInfo? dummyCtorWithAttribute = ctorWithAttribute;
-
- constructors = type.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance);
- foreach (ConstructorInfo constructor in constructors)
+ // Search for non-public ctors with [JsonConstructor].
+ foreach (ConstructorInfo constructor in type.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance))
{
if (HasJsonConstructorAttribute(constructor))
{
- if (dummyCtorWithAttribute != null)
+ if (ctorWithAttribute != null)
{
deserializationCtor = null;
return false;
}
- dummyCtorWithAttribute = constructor;
+ ctorWithAttribute = constructor;
}
}
category: JsonConstants.SystemTextJsonSourceGenerationName,
defaultSeverity: DiagnosticSeverity.Error,
isEnabledByDefault: true);
+
+ public static DiagnosticDescriptor JsonConstructorInaccessible { get; } = new DiagnosticDescriptor(
+ id: "SYSLIB1222",
+ title: new LocalizableResourceString(nameof(SR.JsonConstructorInaccessibleTitle), SR.ResourceManager, typeof(FxResources.System.Text.Json.SourceGeneration.SR)),
+ messageFormat: new LocalizableResourceString(nameof(SR.JsonConstructorInaccessibleMessageFormat), SR.ResourceManager, typeof(FxResources.System.Text.Json.SourceGeneration.SR)),
+ category: JsonConstants.SystemTextJsonSourceGenerationName,
+ defaultSeverity: DiagnosticSeverity.Warning,
+ isEnabledByDefault: true);
}
}
}
if (!TryGetDeserializationConstructor(type, useDefaultCtorInAnnotatedStructs, out IMethodSymbol? constructor))
{
- classType = ClassType.TypeUnsupportedBySourceGen;
ReportDiagnostic(DiagnosticDescriptors.MultipleJsonConstructorAttribute, typeLocation, type.ToDisplayString());
}
- else
+ else if (constructor != null && !IsSymbolAccessibleWithin(constructor, within: contextType))
{
- classType = ClassType.Object;
+ ReportDiagnostic(DiagnosticDescriptors.JsonConstructorInaccessible, typeLocation, type.ToDisplayString());
+ constructor = null;
+ }
- implementsIJsonOnSerializing = _knownSymbols.IJsonOnSerializingType.IsAssignableFrom(type);
- implementsIJsonOnSerialized = _knownSymbols.IJsonOnSerializedType.IsAssignableFrom(type);
+ classType = ClassType.Object;
- ctorParamSpecs = ParseConstructorParameters(typeToGenerate, constructor, out constructionStrategy, out constructorSetsRequiredMembers);
- propertySpecs = ParsePropertyGenerationSpecs(contextType, typeToGenerate, typeLocation, options, out hasExtensionDataProperty);
- propertyInitializerSpecs = ParsePropertyInitializers(ctorParamSpecs, propertySpecs, constructorSetsRequiredMembers, ref constructionStrategy);
- }
+ implementsIJsonOnSerializing = _knownSymbols.IJsonOnSerializingType.IsAssignableFrom(type);
+ implementsIJsonOnSerialized = _knownSymbols.IJsonOnSerializedType.IsAssignableFrom(type);
+
+ ctorParamSpecs = ParseConstructorParameters(typeToGenerate, constructor, out constructionStrategy, out constructorSetsRequiredMembers);
+ propertySpecs = ParsePropertyGenerationSpecs(contextType, typeToGenerate, typeLocation, options, out hasExtensionDataProperty);
+ propertyInitializerSpecs = ParsePropertyInitializers(ctorParamSpecs, propertySpecs, constructorSetsRequiredMembers, ref constructionStrategy);
}
var typeRef = new TypeRef(type);
memberInfo,
hasJsonInclude,
out bool isReadOnly,
- out bool isPublic,
+ out bool isAccessible,
out bool isRequired,
out bool canUseGetter,
out bool canUseSetter,
NameSpecifiedInSourceCode = memberInfo.MemberNameNeedsAtSign() ? "@" + memberInfo.Name : memberInfo.Name,
MemberName = memberInfo.Name,
IsProperty = memberInfo is IPropertySymbol,
- IsPublic = isPublic,
+ IsPublic = isAccessible,
IsVirtual = memberInfo.IsVirtual(),
JsonPropertyName = jsonPropertyName,
RuntimePropertyName = runtimePropertyName,
ISymbol memberInfo,
bool hasJsonInclude,
out bool isReadOnly,
- out bool isPublic,
+ out bool isAccessible,
out bool isRequired,
out bool canUseGetter,
out bool canUseSetter,
out bool hasJsonIncludeButIsInaccessible,
out bool isSetterInitOnly)
{
- isPublic = false;
+ isAccessible = false;
isReadOnly = false;
isRequired = false;
canUseGetter = false;
switch (memberInfo)
{
case IPropertySymbol propertyInfo:
- {
- IMethodSymbol? getMethod = propertyInfo.GetMethod;
- IMethodSymbol? setMethod = propertyInfo.SetMethod;
#if ROSLYN4_4_OR_GREATER
- isRequired = propertyInfo.IsRequired;
+ isRequired = propertyInfo.IsRequired;
#endif
-
- if (getMethod != null)
+ if (propertyInfo.GetMethod is { } getMethod)
+ {
+ if (getMethod.DeclaredAccessibility is Accessibility.Public)
{
- if (getMethod.DeclaredAccessibility is Accessibility.Public)
- {
- isPublic = true;
- canUseGetter = true;
- }
- else if (IsSymbolAccessibleWithin(getMethod, within: contextType))
- {
- canUseGetter = hasJsonInclude;
- }
- else
- {
- hasJsonIncludeButIsInaccessible = hasJsonInclude;
- }
+ isAccessible = true;
+ canUseGetter = true;
}
-
- if (setMethod != null)
+ else if (IsSymbolAccessibleWithin(getMethod, within: contextType))
{
- isSetterInitOnly = setMethod.IsInitOnly;
-
- if (setMethod.DeclaredAccessibility is Accessibility.Public)
- {
- isPublic = true;
- canUseSetter = true;
- }
- else if (IsSymbolAccessibleWithin(setMethod, within: contextType))
- {
- canUseSetter = hasJsonInclude;
- }
- else
- {
- hasJsonIncludeButIsInaccessible = hasJsonInclude;
- }
+ isAccessible = true;
+ canUseGetter = hasJsonInclude;
}
else
{
- isReadOnly = true;
+ hasJsonIncludeButIsInaccessible = hasJsonInclude;
}
}
- break;
- case IFieldSymbol fieldInfo:
+
+ if (propertyInfo.SetMethod is { } setMethod)
{
- isReadOnly = fieldInfo.IsReadOnly;
-#if ROSLYN4_4_OR_GREATER
- isRequired = fieldInfo.IsRequired;
-#endif
- if (fieldInfo.DeclaredAccessibility is Accessibility.Public)
+ isSetterInitOnly = setMethod.IsInitOnly;
+
+ if (setMethod.DeclaredAccessibility is Accessibility.Public)
{
- isPublic = true;
- canUseGetter = true;
- canUseSetter = !isReadOnly;
+ isAccessible = true;
+ canUseSetter = true;
+ }
+ else if (IsSymbolAccessibleWithin(setMethod, within: contextType))
+ {
+ isAccessible = true;
+ canUseSetter = hasJsonInclude;
}
else
{
- // Unlike properties JsonIncludeAttribute is not supported for internal fields.
hasJsonIncludeButIsInaccessible = hasJsonInclude;
}
}
+ else
+ {
+ isReadOnly = true;
+ }
+ break;
+ case IFieldSymbol fieldInfo:
+ isReadOnly = fieldInfo.IsReadOnly;
+#if ROSLYN4_4_OR_GREATER
+ isRequired = fieldInfo.IsRequired;
+#endif
+ if (fieldInfo.DeclaredAccessibility is Accessibility.Public)
+ {
+ isAccessible = true;
+ canUseGetter = true;
+ canUseSetter = !isReadOnly;
+ }
+ else if (IsSymbolAccessibleWithin(fieldInfo, within: contextType))
+ {
+ isAccessible = true;
+ canUseGetter = hasJsonInclude;
+ canUseSetter = hasJsonInclude && !isReadOnly;
+ }
+ else
+ {
+ hasJsonIncludeButIsInaccessible = hasJsonInclude;
+ }
break;
default:
Debug.Fail("Method given an invalid symbol type.");
}
}
- // For correctness, throw if multiple ctors have [JsonConstructor], even if one or more are non-public.
- IMethodSymbol? dummyCtorWithAttribute = ctorWithAttribute;
-
+ // Search for non-public ctors with [JsonConstructor].
foreach (IMethodSymbol constructor in namedType.GetExplicitlyDeclaredInstanceConstructors().Where(ctor => ctor.DeclaredAccessibility is not Accessibility.Public))
{
if (constructor.ContainsAttribute(_knownSymbols.JsonConstructorAttributeType))
{
- if (dummyCtorWithAttribute != null)
+ if (ctorWithAttribute != null)
{
deserializationCtor = null;
return false;
}
- dummyCtorWithAttribute = constructor;
+ ctorWithAttribute = constructor;
}
}
<data name="JsonUnsupportedLanguageVersionMessageFormat" xml:space="preserve">
<value>The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater.</value>
</data>
+ <data name="JsonConstructorInaccessibleTitle" xml:space="preserve">
+ <value>Constructor annotated with JsonConstructorAttribute is inaccessible.</value>
+ </data>
+ <data name="JsonConstructorInaccessibleMessageFormat" xml:space="preserve">
+ <value>The constructor on type '{0}' has been annotated with JsonConstructorAttribute but is not accessible by the source generator.</value>
+ </data>
</root>
<target state="translated">Deserializace vlastností pouze pro inicializaci se v současnosti v režimu generování zdroje nepodporuje.</target>
<note />
</trans-unit>
+ <trans-unit id="JsonConstructorInaccessibleMessageFormat">
+ <source>The constructor on type '{0}' has been annotated with JsonConstructorAttribute but is not accessible by the source generator.</source>
+ <target state="new">The constructor on type '{0}' has been annotated with JsonConstructorAttribute but is not accessible by the source generator.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="JsonConstructorInaccessibleTitle">
+ <source>Constructor annotated with JsonConstructorAttribute is inaccessible.</source>
+ <target state="new">Constructor annotated with JsonConstructorAttribute is inaccessible.</target>
+ <note />
+ </trans-unit>
<trans-unit id="JsonConverterAttributeInvalidTypeMessageFormat">
<source>The 'JsonConverterAttribute' type '{0}' specified on member '{1}' is not a converter type or does not contain an accessible parameterless constructor.</source>
<target state="translated">Typ JsonConverterAttribute {0} specifikovaný u členu {1} není typem konvertoru nebo neobsahuje přístupný konstruktor bez parametrů.</target>
<target state="translated">Die Deserialisierung von reinen init-Eigenschaften wird im Quellgenerierungsmodus derzeit nicht unterstützt.</target>
<note />
</trans-unit>
+ <trans-unit id="JsonConstructorInaccessibleMessageFormat">
+ <source>The constructor on type '{0}' has been annotated with JsonConstructorAttribute but is not accessible by the source generator.</source>
+ <target state="new">The constructor on type '{0}' has been annotated with JsonConstructorAttribute but is not accessible by the source generator.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="JsonConstructorInaccessibleTitle">
+ <source>Constructor annotated with JsonConstructorAttribute is inaccessible.</source>
+ <target state="new">Constructor annotated with JsonConstructorAttribute is inaccessible.</target>
+ <note />
+ </trans-unit>
<trans-unit id="JsonConverterAttributeInvalidTypeMessageFormat">
<source>The 'JsonConverterAttribute' type '{0}' specified on member '{1}' is not a converter type or does not contain an accessible parameterless constructor.</source>
<target state="translated">Der für den Member "{1}" angegebene JsonConverterAttribute-Typ "{0}" ist kein Konvertertyp oder enthält keinen parameterlosen Konstruktor, auf den zugegriffen werden kann.</target>
<target state="translated">Actualmente no se admite la deserialización de propiedades de solo inicialización en el modo de generación de origen.</target>
<note />
</trans-unit>
+ <trans-unit id="JsonConstructorInaccessibleMessageFormat">
+ <source>The constructor on type '{0}' has been annotated with JsonConstructorAttribute but is not accessible by the source generator.</source>
+ <target state="new">The constructor on type '{0}' has been annotated with JsonConstructorAttribute but is not accessible by the source generator.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="JsonConstructorInaccessibleTitle">
+ <source>Constructor annotated with JsonConstructorAttribute is inaccessible.</source>
+ <target state="new">Constructor annotated with JsonConstructorAttribute is inaccessible.</target>
+ <note />
+ </trans-unit>
<trans-unit id="JsonConverterAttributeInvalidTypeMessageFormat">
<source>The 'JsonConverterAttribute' type '{0}' specified on member '{1}' is not a converter type or does not contain an accessible parameterless constructor.</source>
<target state="translated">El tipo “JsonConverterAttribute” “{0}” especificado en el miembro “{1}” no es un tipo de convertidor o no contiene un constructor sin parámetros accesible.</target>
<target state="translated">La désérialisation des propriétés d’initialisation uniquement n’est actuellement pas prise en charge en mode de génération de source.</target>
<note />
</trans-unit>
+ <trans-unit id="JsonConstructorInaccessibleMessageFormat">
+ <source>The constructor on type '{0}' has been annotated with JsonConstructorAttribute but is not accessible by the source generator.</source>
+ <target state="new">The constructor on type '{0}' has been annotated with JsonConstructorAttribute but is not accessible by the source generator.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="JsonConstructorInaccessibleTitle">
+ <source>Constructor annotated with JsonConstructorAttribute is inaccessible.</source>
+ <target state="new">Constructor annotated with JsonConstructorAttribute is inaccessible.</target>
+ <note />
+ </trans-unit>
<trans-unit id="JsonConverterAttributeInvalidTypeMessageFormat">
<source>The 'JsonConverterAttribute' type '{0}' specified on member '{1}' is not a converter type or does not contain an accessible parameterless constructor.</source>
<target state="translated">Le type 'JsonConverterAttribute' '{0}' spécifié sur le membre '{1}' n’est pas un type convertisseur ou ne contient pas de constructeur sans paramètre accessible.</target>
<target state="translated">La deserializzazione delle proprietà di sola inizializzazione al momento non è supportata nella modalità di generazione di origine.</target>
<note />
</trans-unit>
+ <trans-unit id="JsonConstructorInaccessibleMessageFormat">
+ <source>The constructor on type '{0}' has been annotated with JsonConstructorAttribute but is not accessible by the source generator.</source>
+ <target state="new">The constructor on type '{0}' has been annotated with JsonConstructorAttribute but is not accessible by the source generator.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="JsonConstructorInaccessibleTitle">
+ <source>Constructor annotated with JsonConstructorAttribute is inaccessible.</source>
+ <target state="new">Constructor annotated with JsonConstructorAttribute is inaccessible.</target>
+ <note />
+ </trans-unit>
<trans-unit id="JsonConverterAttributeInvalidTypeMessageFormat">
<source>The 'JsonConverterAttribute' type '{0}' specified on member '{1}' is not a converter type or does not contain an accessible parameterless constructor.</source>
<target state="translated">Il tipo 'JsonConverterAttribute' '{0}' specificato nel membro '{1}' non è un tipo di convertitore o non contiene un costruttore senza parametri accessibile.</target>
<target state="translated">現在、ソース生成モードでは init-only プロパティの逆シリアル化はサポートされていません。</target>
<note />
</trans-unit>
+ <trans-unit id="JsonConstructorInaccessibleMessageFormat">
+ <source>The constructor on type '{0}' has been annotated with JsonConstructorAttribute but is not accessible by the source generator.</source>
+ <target state="new">The constructor on type '{0}' has been annotated with JsonConstructorAttribute but is not accessible by the source generator.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="JsonConstructorInaccessibleTitle">
+ <source>Constructor annotated with JsonConstructorAttribute is inaccessible.</source>
+ <target state="new">Constructor annotated with JsonConstructorAttribute is inaccessible.</target>
+ <note />
+ </trans-unit>
<trans-unit id="JsonConverterAttributeInvalidTypeMessageFormat">
<source>The 'JsonConverterAttribute' type '{0}' specified on member '{1}' is not a converter type or does not contain an accessible parameterless constructor.</source>
<target state="translated">メンバー '{1}' で指定されている 'JsonConverterAttribute' 型 '{0}' はコンバーター型ではないか、アクセス可能なパラメーターなしのコンストラクターを含んでいません。</target>
<target state="translated">초기화 전용 속성의 역직렬화는 현재 원본 생성 모드에서 지원되지 않습니다.</target>
<note />
</trans-unit>
+ <trans-unit id="JsonConstructorInaccessibleMessageFormat">
+ <source>The constructor on type '{0}' has been annotated with JsonConstructorAttribute but is not accessible by the source generator.</source>
+ <target state="new">The constructor on type '{0}' has been annotated with JsonConstructorAttribute but is not accessible by the source generator.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="JsonConstructorInaccessibleTitle">
+ <source>Constructor annotated with JsonConstructorAttribute is inaccessible.</source>
+ <target state="new">Constructor annotated with JsonConstructorAttribute is inaccessible.</target>
+ <note />
+ </trans-unit>
<trans-unit id="JsonConverterAttributeInvalidTypeMessageFormat">
<source>The 'JsonConverterAttribute' type '{0}' specified on member '{1}' is not a converter type or does not contain an accessible parameterless constructor.</source>
<target state="translated">'{1}' 멤버에 지정된 'JsonConverterAttribute' 형식 '{0}'이(가) 변환기 형식이 아니거나 액세스 가능한 매개 변수가 없는 생성자를 포함하지 않습니다.</target>
<target state="translated">Deserializacja właściwości tylko do inicjowania nie jest obecnie obsługiwana w trybie generowania źródła.</target>
<note />
</trans-unit>
+ <trans-unit id="JsonConstructorInaccessibleMessageFormat">
+ <source>The constructor on type '{0}' has been annotated with JsonConstructorAttribute but is not accessible by the source generator.</source>
+ <target state="new">The constructor on type '{0}' has been annotated with JsonConstructorAttribute but is not accessible by the source generator.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="JsonConstructorInaccessibleTitle">
+ <source>Constructor annotated with JsonConstructorAttribute is inaccessible.</source>
+ <target state="new">Constructor annotated with JsonConstructorAttribute is inaccessible.</target>
+ <note />
+ </trans-unit>
<trans-unit id="JsonConverterAttributeInvalidTypeMessageFormat">
<source>The 'JsonConverterAttribute' type '{0}' specified on member '{1}' is not a converter type or does not contain an accessible parameterless constructor.</source>
<target state="translated">Typ „{0}” „JsonConverterAttribute” określony w przypadku składowej „{1}” nie jest typem konwertera lub nie zawiera dostępnego konstruktora bez parametrów.</target>
<target state="translated">A desserialização de propriedades apenas de inicialização não é atualmente suportada no modo de geração de origem.</target>
<note />
</trans-unit>
+ <trans-unit id="JsonConstructorInaccessibleMessageFormat">
+ <source>The constructor on type '{0}' has been annotated with JsonConstructorAttribute but is not accessible by the source generator.</source>
+ <target state="new">The constructor on type '{0}' has been annotated with JsonConstructorAttribute but is not accessible by the source generator.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="JsonConstructorInaccessibleTitle">
+ <source>Constructor annotated with JsonConstructorAttribute is inaccessible.</source>
+ <target state="new">Constructor annotated with JsonConstructorAttribute is inaccessible.</target>
+ <note />
+ </trans-unit>
<trans-unit id="JsonConverterAttributeInvalidTypeMessageFormat">
<source>The 'JsonConverterAttribute' type '{0}' specified on member '{1}' is not a converter type or does not contain an accessible parameterless constructor.</source>
<target state="translated">O tipo "JsonConverterAttribute" "{0}" especificado no membro "{1}" não é um tipo de conversor ou não contém um construtor sem parâmetros acessível.</target>
<target state="translated">Десериализация свойств, предназначенных только для инициализации, сейчас не поддерживается в режиме создания исходного кода.</target>
<note />
</trans-unit>
+ <trans-unit id="JsonConstructorInaccessibleMessageFormat">
+ <source>The constructor on type '{0}' has been annotated with JsonConstructorAttribute but is not accessible by the source generator.</source>
+ <target state="new">The constructor on type '{0}' has been annotated with JsonConstructorAttribute but is not accessible by the source generator.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="JsonConstructorInaccessibleTitle">
+ <source>Constructor annotated with JsonConstructorAttribute is inaccessible.</source>
+ <target state="new">Constructor annotated with JsonConstructorAttribute is inaccessible.</target>
+ <note />
+ </trans-unit>
<trans-unit id="JsonConverterAttributeInvalidTypeMessageFormat">
<source>The 'JsonConverterAttribute' type '{0}' specified on member '{1}' is not a converter type or does not contain an accessible parameterless constructor.</source>
<target state="translated">Тип "JsonConverterAttribute" "{0}", указанный в элементе "{1}", не является типом преобразователя или не содержит доступного конструктора без параметров.</target>
<target state="translated">Yalnızca başlangıç özelliklerini seri durumdan çıkarma şu anda kaynak oluşturma modunda desteklenmiyor.</target>
<note />
</trans-unit>
+ <trans-unit id="JsonConstructorInaccessibleMessageFormat">
+ <source>The constructor on type '{0}' has been annotated with JsonConstructorAttribute but is not accessible by the source generator.</source>
+ <target state="new">The constructor on type '{0}' has been annotated with JsonConstructorAttribute but is not accessible by the source generator.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="JsonConstructorInaccessibleTitle">
+ <source>Constructor annotated with JsonConstructorAttribute is inaccessible.</source>
+ <target state="new">Constructor annotated with JsonConstructorAttribute is inaccessible.</target>
+ <note />
+ </trans-unit>
<trans-unit id="JsonConverterAttributeInvalidTypeMessageFormat">
<source>The 'JsonConverterAttribute' type '{0}' specified on member '{1}' is not a converter type or does not contain an accessible parameterless constructor.</source>
<target state="translated">'{1}' üyesi üzerinde belirtilen 'JsonConverterAttribute' '{0}' türü dönüştürücü türü değil veya erişilebilir parametresiz bir oluşturucu içermiyor.</target>
<target state="translated">源生成模式当前不支持仅初始化属性的反序列化。</target>
<note />
</trans-unit>
+ <trans-unit id="JsonConstructorInaccessibleMessageFormat">
+ <source>The constructor on type '{0}' has been annotated with JsonConstructorAttribute but is not accessible by the source generator.</source>
+ <target state="new">The constructor on type '{0}' has been annotated with JsonConstructorAttribute but is not accessible by the source generator.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="JsonConstructorInaccessibleTitle">
+ <source>Constructor annotated with JsonConstructorAttribute is inaccessible.</source>
+ <target state="new">Constructor annotated with JsonConstructorAttribute is inaccessible.</target>
+ <note />
+ </trans-unit>
<trans-unit id="JsonConverterAttributeInvalidTypeMessageFormat">
<source>The 'JsonConverterAttribute' type '{0}' specified on member '{1}' is not a converter type or does not contain an accessible parameterless constructor.</source>
<target state="translated">在成员 "{1}" 上指定的 "JsonConverterAttribute" 类型 "{0}" 不是转换器类型或不包含可访问的无参数构造函数。</target>
<target state="translated">來源產生模式目前不支援 init-only 屬性的還原序列化。</target>
<note />
</trans-unit>
+ <trans-unit id="JsonConstructorInaccessibleMessageFormat">
+ <source>The constructor on type '{0}' has been annotated with JsonConstructorAttribute but is not accessible by the source generator.</source>
+ <target state="new">The constructor on type '{0}' has been annotated with JsonConstructorAttribute but is not accessible by the source generator.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="JsonConstructorInaccessibleTitle">
+ <source>Constructor annotated with JsonConstructorAttribute is inaccessible.</source>
+ <target state="new">Constructor annotated with JsonConstructorAttribute is inaccessible.</target>
+ <note />
+ </trans-unit>
<trans-unit id="JsonConverterAttributeInvalidTypeMessageFormat">
<source>The 'JsonConverterAttribute' type '{0}' specified on member '{1}' is not a converter type or does not contain an accessible parameterless constructor.</source>
<target state="translated">成員 '{1}' 上指定的 'JsonConverterAttribute' 類型 '{0}' 不是轉換器類型,或不包含可存取的無參數建構函式。</target>
<data name="SerializeTypeInstanceNotSupported" xml:space="preserve">
<value>Serialization and deserialization of '{0}' instances is not supported.</value>
</data>
- <data name="JsonIncludeOnNonPublicInvalid" xml:space="preserve">
- <value>The non-public property '{0}' on type '{1}' is annotated with 'JsonIncludeAttribute' which is invalid.</value>
+ <data name="JsonIncludeOnInaccessibleProperty" xml:space="preserve">
+ <value>The property '{0}' on type '{1}' which is annotated with 'JsonIncludeAttribute' is not accesible by the source generator.</value>
</data>
<data name="CannotSerializeInvalidMember" xml:space="preserve">
<value>The type '{0}' of property '{1}' on type '{2}' is invalid for serialization or deserialization because it is a pointer type, is a ref struct, or contains generic parameters that have not been replaced by specific types.</value>
continue;
}
- // For now we only support public properties (i.e. setter and/or getter is public).
+ bool hasJsonIncludeAttribute = propertyInfo.GetCustomAttribute<JsonIncludeAttribute>(inherit: false) != null;
+
+ // Only include properties that either have a public getter or a public setter or have the JsonIncludeAttribute set.
if (propertyInfo.GetMethod?.IsPublic == true ||
- propertyInfo.SetMethod?.IsPublic == true)
+ propertyInfo.SetMethod?.IsPublic == true ||
+ hasJsonIncludeAttribute)
{
AddMember(
typeInfo,
typeToConvert: propertyInfo.PropertyType,
memberInfo: propertyInfo,
shouldCheckMembersForRequiredMemberAttribute,
+ hasJsonIncludeAttribute,
ref state);
}
- else
- {
- if (propertyInfo.GetCustomAttribute<JsonIncludeAttribute>(inherit: false) != null)
- {
- ThrowHelper.ThrowInvalidOperationException_JsonIncludeOnNonPublicInvalid(propertyInfo.Name, currentType);
- }
-
- // Non-public properties should not be included for (de)serialization.
- }
}
foreach (FieldInfo fieldInfo in currentType.GetFields(BindingFlags))
{
- bool hasJsonInclude = fieldInfo.GetCustomAttribute<JsonIncludeAttribute>(inherit: false) != null;
-
- if (fieldInfo.IsPublic)
- {
- if (hasJsonInclude || typeInfo.Options.IncludeFields)
- {
- AddMember(
- typeInfo,
- typeToConvert: fieldInfo.FieldType,
- memberInfo: fieldInfo,
- shouldCheckMembersForRequiredMemberAttribute,
- ref state);
- }
- }
- else
+ bool hasJsonIncludeAtribute = fieldInfo.GetCustomAttribute<JsonIncludeAttribute>(inherit: false) != null;
+ if (hasJsonIncludeAtribute || (fieldInfo.IsPublic && typeInfo.Options.IncludeFields))
{
- if (hasJsonInclude)
- {
- ThrowHelper.ThrowInvalidOperationException_JsonIncludeOnNonPublicInvalid(fieldInfo.Name, currentType);
- }
-
- // Non-public fields should not be included for (de)serialization.
+ AddMember(
+ typeInfo,
+ typeToConvert: fieldInfo.FieldType,
+ memberInfo: fieldInfo,
+ shouldCheckMembersForRequiredMemberAttribute,
+ hasJsonIncludeAtribute,
+ ref state);
}
}
}
Type typeToConvert,
MemberInfo memberInfo,
bool shouldCheckForRequiredKeyword,
+ bool hasJsonIncludeAttribute,
ref JsonTypeInfo.PropertyHierarchyResolutionState state)
{
- JsonPropertyInfo? jsonPropertyInfo = CreatePropertyInfo(typeInfo, typeToConvert, memberInfo, typeInfo.Options, shouldCheckForRequiredKeyword);
+ JsonPropertyInfo? jsonPropertyInfo = CreatePropertyInfo(typeInfo, typeToConvert, memberInfo, typeInfo.Options, shouldCheckForRequiredKeyword, hasJsonIncludeAttribute);
if (jsonPropertyInfo == null)
{
// ignored invalid property
Type typeToConvert,
MemberInfo memberInfo,
JsonSerializerOptions options,
- bool shouldCheckForRequiredKeyword)
+ bool shouldCheckForRequiredKeyword,
+ bool hasJsonIncludeAttribute)
{
JsonIgnoreCondition? ignoreCondition = memberInfo.GetCustomAttribute<JsonIgnoreAttribute>(inherit: false)?.Condition;
}
JsonPropertyInfo jsonPropertyInfo = typeInfo.CreatePropertyUsingReflection(typeToConvert);
- PopulatePropertyInfo(jsonPropertyInfo, memberInfo, customConverter, ignoreCondition, shouldCheckForRequiredKeyword);
+ PopulatePropertyInfo(jsonPropertyInfo, memberInfo, customConverter, ignoreCondition, shouldCheckForRequiredKeyword, hasJsonIncludeAttribute);
return jsonPropertyInfo;
}
[RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
[RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
- private static void PopulatePropertyInfo(JsonPropertyInfo jsonPropertyInfo, MemberInfo memberInfo, JsonConverter? customConverter, JsonIgnoreCondition? ignoreCondition, bool shouldCheckForRequiredKeyword)
+ private static void PopulatePropertyInfo(
+ JsonPropertyInfo jsonPropertyInfo,
+ MemberInfo memberInfo,
+ JsonConverter? customConverter,
+ JsonIgnoreCondition? ignoreCondition,
+ bool shouldCheckForRequiredKeyword,
+ bool hasJsonIncludeAttribute)
{
Debug.Assert(jsonPropertyInfo.AttributeProvider == null);
if (ignoreCondition != JsonIgnoreCondition.Always)
{
- jsonPropertyInfo.DetermineReflectionPropertyAccessors(memberInfo);
+ jsonPropertyInfo.DetermineReflectionPropertyAccessors(memberInfo, useNonPublicAccessors: hasJsonIncludeAttribute);
}
jsonPropertyInfo.IgnoreCondition = ignoreCondition;
[RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
[RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
- internal static void DeterminePropertyAccessors<T>(JsonPropertyInfo<T> jsonPropertyInfo, MemberInfo memberInfo)
+ internal static void DeterminePropertyAccessors<T>(JsonPropertyInfo<T> jsonPropertyInfo, MemberInfo memberInfo, bool useNonPublicAccessors)
{
Debug.Assert(memberInfo is FieldInfo or PropertyInfo);
switch (memberInfo)
{
case PropertyInfo propertyInfo:
- bool useNonPublicAccessors = propertyInfo.GetCustomAttribute<JsonIncludeAttribute>(inherit: false) != null;
-
MethodInfo? getMethod = propertyInfo.GetMethod;
if (getMethod != null && (getMethod.IsPublic || useNonPublicAccessors))
{
break;
case FieldInfo fieldInfo:
- Debug.Assert(fieldInfo.IsPublic);
+ Debug.Assert(fieldInfo.IsPublic || useNonPublicAccessors);
jsonPropertyInfo.Get = MemberAccessor.CreateFieldGetter<T>(fieldInfo);
if (jsonPropertyInfo.SrcGen_HasJsonInclude)
{
Debug.Assert(jsonPropertyInfo.MemberName != null, "MemberName is not set by source gen");
- ThrowHelper.ThrowInvalidOperationException_JsonIncludeOnNonPublicInvalid(jsonPropertyInfo.MemberName, jsonPropertyInfo.DeclaringType);
+ ThrowHelper.ThrowInvalidOperationException_JsonIncludeOnInaccessibleProperty(jsonPropertyInfo.MemberName, jsonPropertyInfo.DeclaringType);
}
continue;
[RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
[RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
- internal abstract void DetermineReflectionPropertyAccessors(MemberInfo memberInfo);
+ internal abstract void DetermineReflectionPropertyAccessors(MemberInfo memberInfo, bool useNonPublicAccessors);
private void CacheNameAsUtf8BytesAndEscapedNameSection()
{
[RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
[RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
- internal override void DetermineReflectionPropertyAccessors(MemberInfo memberInfo)
- => DefaultJsonTypeInfoResolver.DeterminePropertyAccessors<T>(this, memberInfo);
+ internal override void DetermineReflectionPropertyAccessors(MemberInfo memberInfo, bool useNonPublicAccessors)
+ => DefaultJsonTypeInfoResolver.DeterminePropertyAccessors<T>(this, memberInfo, useNonPublicAccessors);
+
private protected override void DetermineEffectiveConverter(JsonTypeInfo jsonTypeInfo)
{
Debug.Assert(jsonTypeInfo is JsonTypeInfo<T>);
Debug.Assert(type != null);
Debug.Assert(!type.IsAbstract);
- Debug.Assert(constructor.IsPublic && !constructor.IsStatic);
+ Debug.Assert(!constructor.IsStatic);
ParameterInfo[] parameters = constructor.GetParameters();
int parameterCount = parameters.Length;
}
[DoesNotReturn]
- public static void ThrowInvalidOperationException_JsonIncludeOnNonPublicInvalid(string memberName, Type declaringType)
+ public static void ThrowInvalidOperationException_JsonIncludeOnInaccessibleProperty(string memberName, Type declaringType)
{
- throw new InvalidOperationException(SR.Format(SR.JsonIncludeOnNonPublicInvalid, memberName, declaringType));
+ throw new InvalidOperationException(SR.Format(SR.JsonIncludeOnInaccessibleProperty, memberName, declaringType));
}
[DoesNotReturn]
{
public abstract partial class ConstructorTests
{
- [Fact]
- public async Task NonPublicCtors_NotSupported()
+ [Theory]
+ [InlineData(typeof(PrivateParameterlessCtor))]
+ [InlineData(typeof(InternalParameterlessCtor))]
+ [InlineData(typeof(ProtectedParameterlessCtor))]
+ [InlineData(typeof(PrivateParameterizedCtor))]
+ [InlineData(typeof(InternalParameterizedCtor))]
+ [InlineData(typeof(ProtectedParameterizedCtor))]
+ public async Task NonPublicCtors_NotSupported(Type type)
{
- async Task RunTestAsync<T>()
+ NotSupportedException ex = await Assert.ThrowsAsync<NotSupportedException>(() => Serializer.DeserializeWrapper("{}", type));
+ Assert.Contains("JsonConstructorAttribute", ex.ToString());
+ }
+
+ [Theory]
+ [InlineData(typeof(PrivateParameterizedCtor_WithAttribute), false)]
+ [InlineData(typeof(InternalParameterizedCtor_WithAttribute), true)]
+ [InlineData(typeof(ProtectedParameterizedCtor_WithAttribute), false)]
+ public async Task NonPublicCtors_WithJsonConstructorAttribute_WorksAsExpected(Type type, bool isAccessibleBySourceGen)
+ {
+ if (!Serializer.IsSourceGeneratedSerializer || isAccessibleBySourceGen)
+ {
+ object? result = await Serializer.DeserializeWrapper("{}", type);
+ Assert.IsType(type, result);
+ }
+ else
{
- NotSupportedException ex = await Assert.ThrowsAsync<NotSupportedException>(() => Serializer.DeserializeWrapper<T>("{}"));
+ NotSupportedException ex = await Assert.ThrowsAsync<NotSupportedException>(() => Serializer.DeserializeWrapper("{}", type));
Assert.Contains("JsonConstructorAttribute", ex.ToString());
}
-
- await RunTestAsync<PrivateParameterlessCtor>();
- await RunTestAsync<InternalParameterlessCtor>();
- await RunTestAsync<ProtectedParameterlessCtor>();
- await RunTestAsync<PrivateParameterizedCtor>();
- await RunTestAsync<InternalParameterizedCtor>();
- await RunTestAsync<ProtectedParameterizedCtor>();
- await RunTestAsync<PrivateParameterizedCtor_WithAttribute>();
- await RunTestAsync<InternalParameterizedCtor_WithAttribute>();
- await RunTestAsync<ProtectedParameterizedCtor_WithAttribute>();
}
[Fact]
/// </summary>
public abstract JsonSerializerOptions DefaultOptions { get; }
+ public bool IsSourceGeneratedSerializer => DefaultOptions.TypeInfoResolver is JsonSerializerContext;
+
/// <summary>
/// Do the deserialize methods allow a value of 'null'.
/// For example, deserializing JSON to a String supports null by returning a 'null' String reference from a literal value of "null".
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
+using System.Reflection;
using System.Text.Json.Serialization.Metadata;
using System.Threading.Tasks;
using Xunit;
}
[Theory]
- [InlineData(typeof(ClassWithPrivateProperty_WithJsonIncludeProperty))]
- [InlineData(typeof(ClassWithInternalProperty_WithJsonIncludeProperty))]
- [InlineData(typeof(ClassWithProtectedProperty_WithJsonIncludeProperty))]
- [InlineData(typeof(ClassWithPrivateField_WithJsonIncludeProperty))]
- [InlineData(typeof(ClassWithInternalField_WithJsonIncludeProperty))]
- [InlineData(typeof(ClassWithProtectedField_WithJsonIncludeProperty))]
- [InlineData(typeof(ClassWithPrivate_InitOnlyProperty_WithJsonIncludeProperty))]
- [InlineData(typeof(ClassWithInternal_InitOnlyProperty_WithJsonIncludeProperty))]
- [InlineData(typeof(ClassWithProtected_InitOnlyProperty_WithJsonIncludeProperty))]
- public virtual async Task NonPublicProperty_WithJsonInclude_Invalid(Type type)
- {
- InvalidOperationException ex = await Assert.ThrowsAsync<InvalidOperationException>(async () => await Serializer.DeserializeWrapper("{}", type));
- string exAsStr = ex.ToString();
- Assert.Contains("MyString", exAsStr);
- Assert.Contains(type.ToString(), exAsStr);
- Assert.Contains("JsonIncludeAttribute", exAsStr);
-
- ex = await Assert.ThrowsAsync<InvalidOperationException>(async () => await Serializer.SerializeWrapper(Activator.CreateInstance(type), type));
- exAsStr = ex.ToString();
- Assert.Contains("MyString", exAsStr);
- Assert.Contains(type.ToString(), exAsStr);
- Assert.Contains("JsonIncludeAttribute", exAsStr);
+ [InlineData(typeof(ClassWithPrivateProperty_WithJsonIncludeProperty), false)]
+ [InlineData(typeof(ClassWithInternalProperty_WithJsonIncludeProperty), true)]
+ [InlineData(typeof(ClassWithProtectedProperty_WithJsonIncludeProperty), false)]
+ [InlineData(typeof(ClassWithPrivateField_WithJsonIncludeProperty), false)]
+ [InlineData(typeof(ClassWithInternalField_WithJsonIncludeProperty), true)]
+ [InlineData(typeof(ClassWithProtectedField_WithJsonIncludeProperty), false)]
+ [InlineData(typeof(ClassWithPrivate_InitOnlyProperty_WithJsonIncludeProperty), false)]
+ [InlineData(typeof(ClassWithInternal_InitOnlyProperty_WithJsonIncludeProperty), true)]
+ [InlineData(typeof(ClassWithProtected_InitOnlyProperty_WithJsonIncludeProperty), false)]
+ public virtual async Task NonPublicProperty_JsonInclude_WorksAsExpected(Type type, bool isAccessibleBySourceGen)
+ {
+ if (!Serializer.IsSourceGeneratedSerializer || isAccessibleBySourceGen)
+ {
+ string json = """{"MyString":"value"}""";
+ MemberInfo memberInfo = type.GetMember("MyString", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)[0];
+
+ object result = await Serializer.DeserializeWrapper("""{"MyString":"value"}""", type);
+ Assert.IsType(type, result);
+ Assert.Equal(memberInfo is PropertyInfo p ? p.GetValue(result) : ((FieldInfo)memberInfo).GetValue(result), "value");
+
+ string actualJson = await Serializer.SerializeWrapper(result, type);
+ Assert.Equal(json, actualJson);
+ }
+ else
+ {
+ InvalidOperationException ex = await Assert.ThrowsAsync<InvalidOperationException>(async () => await Serializer.DeserializeWrapper("{}", type));
+ string exAsStr = ex.ToString();
+ Assert.Contains("MyString", exAsStr);
+ Assert.Contains(type.ToString(), exAsStr);
+ Assert.Contains("JsonIncludeAttribute", exAsStr);
+
+ ex = await Assert.ThrowsAsync<InvalidOperationException>(async () => await Serializer.SerializeWrapper(Activator.CreateInstance(type), type));
+ exAsStr = ex.ToString();
+ Assert.Contains("MyString", exAsStr);
+ Assert.Contains(type.ToString(), exAsStr);
+ Assert.Contains("JsonIncludeAttribute", exAsStr);
+ }
}
public class ClassWithPrivateProperty_WithJsonIncludeProperty
public class ClassWithInternalProperty_WithJsonIncludeProperty
{
[JsonInclude]
- internal string MyString { get; }
+ internal string MyString { get; set; }
}
public class ClassWithProtectedProperty_WithJsonIncludeProperty
}
[Theory]
- [InlineData(typeof(ClassWithPrivateProperty_WithJsonIncludeProperty))]
- [InlineData(typeof(ClassWithInternalProperty_WithJsonIncludeProperty))]
- [InlineData(typeof(ClassWithProtectedProperty_WithJsonIncludeProperty))]
- [InlineData(typeof(ClassWithPrivateField_WithJsonIncludeProperty))]
- [InlineData(typeof(ClassWithInternalField_WithJsonIncludeProperty))]
- [InlineData(typeof(ClassWithProtectedField_WithJsonIncludeProperty))]
- [InlineData(typeof(ClassWithPrivate_InitOnlyProperty_WithJsonIncludeProperty))]
- [InlineData(typeof(ClassWithInternal_InitOnlyProperty_WithJsonIncludeProperty))]
- [InlineData(typeof(ClassWithProtected_InitOnlyProperty_WithJsonIncludeProperty))]
- public override async Task NonPublicProperty_WithJsonInclude_Invalid(Type type)
- {
- // Exception messages direct users to use JsonSourceGenerationMode.Metadata to see a more detailed error.
- await Assert.ThrowsAsync<InvalidOperationException>(async () => await Serializer.DeserializeWrapper("{}", type));
- await Assert.ThrowsAsync<InvalidOperationException>(async () => await Serializer.SerializeWrapper(Activator.CreateInstance(type), type));
- }
-
- [Theory]
[InlineData(typeof(ClassWithBadIgnoreAttribute))]
[InlineData(typeof(StructWithBadIgnoreAttribute))]
public override async Task JsonIgnoreCondition_WhenWritingNull_OnValueType_Fail(Type type)
<!-- SYSLIB1038: Suppress JsonInclude on inaccessible members warning -->
<!-- SYSLIB1039: Suppress Polymorphic types not supported warning -->
<!-- SYSLIB1220: Suppress invalid JsonConverterAttribute argument warnings -->
- <NoWarn>$(NoWarn);SYSLIB0020;SYSLIB0049;SYSLIB1034;SYSLIB1037;SYSLIB1038;SYSLIB1039;SYSLIB1220</NoWarn>
+ <!-- SYSLIB1222: Suppress inacessible JsonConstructorAttribute annotations -->
+ <NoWarn>$(NoWarn);SYSLIB0020;SYSLIB0049;SYSLIB1034;SYSLIB1037;SYSLIB1038;SYSLIB1039;SYSLIB1220;SYSLIB1222</NoWarn>
<IgnoreForCI Condition="'$(TargetsMobile)' == 'true' or '$(TargetsLinuxBionic)' == 'true' or '$(TargetArchitecture)' == 'ARMv6'">true</IgnoreForCI>
</PropertyGroup>
internal int internalField = 2;
[JsonInclude]
private int privateField = 4;
+ [JsonInclude]
+ protected int protectedField = 8;
[JsonInclude]
public int Id { get; private set; }
public string PhoneNumber { internal get; set; }
[JsonInclude]
public string Country { private get; set; }
+ [JsonInclude]
+ internal string InternalProperty { get; set; }
+ [JsonInclude]
+ protected string ProtectedProperty { get; set; }
+ [JsonInclude]
+ internal string InternalPropertyWithPrivateGetter { private get; set; }
+ [JsonInclude]
+ internal string InternalPropertyWithPrivateSetter { get; private set; }
public int GetPrivateField() => privateField;
}
return CreateCompilation(source);
}
+ public static Compilation CreateCompilationWithJsonConstructorAttributeAnnotations()
+ {
+ string source = """
+ using System.Text.Json.Serialization;
+
+ namespace HelloWorld
+ {
+ public class ClassWithPublicCtor
+ {
+ [JsonConstructor]
+ public ClassWithPublicCtor() { }
+ }
+
+ public class ClassWithInternalCtor
+ {
+ [JsonConstructor]
+ internal ClassWithInternalCtor() { }
+ }
+
+ public class ClassWithProtectedCtor
+ {
+ [JsonConstructor]
+ protected ClassWithProtectedCtor() { }
+ }
+
+ public class ClassWithPrivateCtor
+ {
+ [JsonConstructor]
+ private ClassWithPrivateCtor() { }
+ }
+
+ [JsonSerializable(typeof(ClassWithPublicCtor))]
+ [JsonSerializable(typeof(ClassWithInternalCtor))]
+ [JsonSerializable(typeof(ClassWithProtectedCtor))]
+ [JsonSerializable(typeof(ClassWithPrivateCtor))]
+ public partial class MyJsonContext : JsonSerializerContext
+ {
+ }
+ }
+ """;
+
+ return CreateCompilation(source);
+ }
+
internal static void AssertEqualDiagnosticMessages(
IEnumerable<DiagnosticData> expectedDiags,
IEnumerable<Diagnostic> actualDiags)
Compilation compilation = CompilationHelper.CreateCompilationWithConstructorInitOnlyProperties();
CompilationHelper.RunJsonSourceGenerator(compilation);
}
-
+
[Fact]
public void DoNotWarnOnClassesWithMixedInitOnlyProperties()
{
Location idLocation = compilation.GetSymbolsWithName("Id").First().Locations[0];
Location address2Location = compilation.GetSymbolsWithName("Address2").First().Locations[0];
Location countryLocation = compilation.GetSymbolsWithName("Country").First().Locations[0];
- Location internalFieldLocation = compilation.GetSymbolsWithName("internalField").First().Locations[0];
Location privateFieldLocation = compilation.GetSymbolsWithName("privateField").First().Locations[0];
+ Location protectedFieldLocation = compilation.GetSymbolsWithName("protectedField").First().Locations[0];
+ Location protectedPropertyLocation = compilation.GetSymbolsWithName("ProtectedProperty").First().Locations[0];
+ Location internalPropertyWithPrivateGetterLocation = compilation.GetSymbolsWithName("InternalPropertyWithPrivateGetter").First().Locations[0];
+ Location internalPropertyWithPrivateSetterLocation = compilation.GetSymbolsWithName("InternalPropertyWithPrivateSetter").First().Locations[0];
var expectedDiagnostics = new DiagnosticData[]
{
new(DiagnosticSeverity.Warning, idLocation, "The member 'Location.Id' has been annotated with the JsonIncludeAttribute but is not visible to the source generator."),
new(DiagnosticSeverity.Warning, address2Location, "The member 'Location.Address2' has been annotated with the JsonIncludeAttribute but is not visible to the source generator."),
new(DiagnosticSeverity.Warning, countryLocation, "The member 'Location.Country' has been annotated with the JsonIncludeAttribute but is not visible to the source generator."),
- new(DiagnosticSeverity.Warning, internalFieldLocation, "The member 'Location.internalField' has been annotated with the JsonIncludeAttribute but is not visible to the source generator."),
new(DiagnosticSeverity.Warning, privateFieldLocation, "The member 'Location.privateField' has been annotated with the JsonIncludeAttribute but is not visible to the source generator."),
+ new(DiagnosticSeverity.Warning, protectedFieldLocation, "The member 'Location.protectedField' has been annotated with the JsonIncludeAttribute but is not visible to the source generator."),
+ new(DiagnosticSeverity.Warning, protectedPropertyLocation, "The member 'Location.ProtectedProperty' has been annotated with the JsonIncludeAttribute but is not visible to the source generator."),
+ new(DiagnosticSeverity.Warning, internalPropertyWithPrivateGetterLocation, "The member 'Location.InternalPropertyWithPrivateGetter' has been annotated with the JsonIncludeAttribute but is not visible to the source generator."),
+ new(DiagnosticSeverity.Warning, internalPropertyWithPrivateSetterLocation, "The member 'Location.InternalPropertyWithPrivateSetter' has been annotated with the JsonIncludeAttribute but is not visible to the source generator."),
};
CompilationHelper.AssertEqualDiagnosticMessages(expectedDiagnostics, result.Diagnostics);
CompilationHelper.AssertEqualDiagnosticMessages(expectedDiagnostics, result.Diagnostics);
}
+
+ [Fact]
+ public void TypesWithJsonConstructorAnnotations_WarnAsExpected()
+ {
+ Compilation compilation = CompilationHelper.CreateCompilationWithJsonConstructorAttributeAnnotations();
+
+ JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation, disableDiagnosticValidation: true);
+
+ Location protectedCtorLocation = compilation.GetSymbolsWithName("ClassWithProtectedCtor").First().Locations[0];
+ Location privateCtorLocation = compilation.GetSymbolsWithName("ClassWithPrivateCtor").First().Locations[0];
+
+ var expectedDiagnostics = new DiagnosticData[]
+ {
+ new(DiagnosticSeverity.Warning, protectedCtorLocation, "The constructor on type 'HelloWorld.ClassWithProtectedCtor' has been annotated with JsonConstructorAttribute but is not accessible by the source generator."),
+ new(DiagnosticSeverity.Warning, privateCtorLocation, "The constructor on type 'HelloWorld.ClassWithPrivateCtor' has been annotated with JsonConstructorAttribute but is not accessible by the source generator."),
+ };
+
+ CompilationHelper.AssertEqualDiagnosticMessages(expectedDiagnostics, result.Diagnostics);
+ }
}
}