Skip to content

Commit

Permalink
Add JSON type hierarchies (dotnet#67961)
Browse files Browse the repository at this point in the history
* Add JSON type hierarchies as a preview feature.

* fix incorrect preview features configuration in ref project

* Add check for conflicting custom type discriminator property names.

* Add null checks & tests to public APIs

* fix typo in constant name

* fix file ordering

* address feedback

* Remove preview features annotation from new APIs
  • Loading branch information
eiriktsarpalis authored and directhex committed Apr 21, 2022
1 parent eeaeebd commit b1bd45f
Show file tree
Hide file tree
Showing 77 changed files with 4,710 additions and 242 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,11 @@ public void Emit()
GenerateTypeInfo(typeGenerationSpec);
}

foreach (TypeGenerationSpec typeGenerationSpec in _currentContext.ImplicitlyRegisteredTypes)
{
GenerateTypeInfo(typeGenerationSpec);
}

string contextName = _currentContext.ContextType.Name;

// Add root context implementation.
Expand Down
39 changes: 34 additions & 5 deletions src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ private sealed class Parser
private const string JsonConverterFactoryFullName = "System.Text.Json.Serialization.JsonConverterFactory";
private const string JsonConverterOfTFullName = "System.Text.Json.Serialization.JsonConverter`1";
private const string JsonArrayFullName = "System.Text.Json.Nodes.JsonArray";
private const string JsonDerivedTypeAttributeFullName = "System.Text.Json.Serialization.JsonDerivedTypeAttribute";
private const string JsonElementFullName = "System.Text.Json.JsonElement";
private const string JsonExtensionDataAttributeFullName = "System.Text.Json.Serialization.JsonExtensionDataAttribute";
private const string JsonNodeFullName = "System.Text.Json.Nodes.JsonNode";
Expand All @@ -40,7 +41,7 @@ private sealed class Parser
private const string JsonPropertyNameAttributeFullName = "System.Text.Json.Serialization.JsonPropertyNameAttribute";
private const string JsonPropertyOrderAttributeFullName = "System.Text.Json.Serialization.JsonPropertyOrderAttribute";
private const string JsonSerializerContextFullName = "System.Text.Json.Serialization.JsonSerializerContext";
private const string JsonSerializerAttributeFullName = "System.Text.Json.Serialization.JsonSerializableAttribute";
private const string JsonSerializableAttributeFullName = "System.Text.Json.Serialization.JsonSerializableAttribute";
private const string JsonSourceGenerationOptionsAttributeFullName = "System.Text.Json.Serialization.JsonSourceGenerationOptionsAttribute";

private const string DateOnlyFullName = "System.DateOnly";
Expand Down Expand Up @@ -176,6 +177,14 @@ private sealed class Parser
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);

private static DiagnosticDescriptor PolymorphismNotSupported { get; } = new DiagnosticDescriptor(
id: "SYSLIB1039",
title: new LocalizableResourceString(nameof(SR.FastPathPolymorphismNotSupportedTitle), SR.ResourceManager, typeof(FxResources.System.Text.Json.SourceGeneration.SR)),
messageFormat: new LocalizableResourceString(nameof(SR.FastPathPolymorphismNotSupportedMessageFormat), 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;
Expand Down Expand Up @@ -240,7 +249,7 @@ public Parser(Compilation compilation, in JsonSourceGenerationContext sourceGene
{
Compilation compilation = _compilation;
INamedTypeSymbol jsonSerializerContextSymbol = compilation.GetBestTypeByMetadataName(JsonSerializerContextFullName);
INamedTypeSymbol jsonSerializableAttributeSymbol = compilation.GetBestTypeByMetadataName(JsonSerializerAttributeFullName);
INamedTypeSymbol jsonSerializableAttributeSymbol = compilation.GetBestTypeByMetadataName(JsonSerializableAttributeFullName);
INamedTypeSymbol jsonSourceGenerationOptionsAttributeSymbol = compilation.GetBestTypeByMetadataName(JsonSourceGenerationOptionsAttributeFullName);
INamedTypeSymbol jsonConverterOfTAttributeSymbol = compilation.GetBestTypeByMetadataName(JsonConverterOfTFullName);

Expand Down Expand Up @@ -551,7 +560,7 @@ private static bool TryGetClassDeclarationList(INamedTypeSymbol typeSymbol, [Not
INamedTypeSymbol attributeContainingTypeSymbol = attributeSymbol.ContainingType;
string fullName = attributeContainingTypeSymbol.ToDisplayString();

if (fullName == "System.Text.Json.Serialization.JsonSerializableAttribute")
if (fullName == JsonSerializableAttributeFullName)
{
return classDeclarationSyntax;
}
Expand Down Expand Up @@ -694,6 +703,7 @@ private TypeGenerationSpec GetOrAddTypeGenerationSpec(Type type, JsonSourceGener
string? converterInstatiationLogic = null;
bool implementsIJsonOnSerialized = false;
bool implementsIJsonOnSerializing = false;
bool isPolymorphic = false;
bool hasInitOnlyProperties = false;
bool hasTypeFactoryConverter = false;
bool hasPropertyFactoryConverters = false;
Expand All @@ -703,7 +713,9 @@ private TypeGenerationSpec GetOrAddTypeGenerationSpec(Type type, JsonSourceGener
foreach (CustomAttributeData attributeData in attributeDataList)
{
Type attributeType = attributeData.AttributeType;
if (attributeType.FullName == JsonNumberHandlingAttributeFullName)
string attributeTypeFullName = attributeType.FullName;

if (attributeTypeFullName == JsonNumberHandlingAttributeFullName)
{
IList<CustomAttributeTypedArgument> ctorArgs = attributeData.ConstructorArguments;
numberHandling = (JsonNumberHandling)ctorArgs[0].Value;
Expand All @@ -718,6 +730,22 @@ private TypeGenerationSpec GetOrAddTypeGenerationSpec(Type type, JsonSourceGener
forType: true,
ref hasTypeFactoryConverter);
}

if (attributeTypeFullName == JsonDerivedTypeAttributeFullName)
{
Debug.Assert(attributeData.ConstructorArguments.Count > 0);
ITypeSymbol derivedTypeSymbol = (ITypeSymbol)attributeData.ConstructorArguments[0].Value;
Type derivedType = derivedTypeSymbol.AsType(_metadataLoadContext);
TypeGenerationSpec derivedTypeSpec = GetOrAddTypeGenerationSpec(derivedType, generationMode);
_implicitlyRegisteredTypes.Add(derivedTypeSpec);

if (!isPolymorphic && generationMode == JsonSourceGenerationMode.Serialization)
{
_typeLevelDiagnostics.Add((type, PolymorphismNotSupported, new string[] { type.FullName }));
}

isPolymorphic = true;
}
}

if (foundDesignTimeCustomConverter)
Expand Down Expand Up @@ -1067,7 +1095,8 @@ void CacheMemberHelper(Location memberLocation)
implementsIJsonOnSerializing : implementsIJsonOnSerializing,
canContainNullableReferenceAnnotations: canContainNullableReferenceAnnotations,
hasTypeFactoryConverter : hasTypeFactoryConverter,
hasPropertyFactoryConverters : hasPropertyFactoryConverters);
hasPropertyFactoryConverters : hasPropertyFactoryConverters,
isPolymorphic : isPolymorphic);

return typeMetadata;
}
Expand Down
6 changes: 6 additions & 0 deletions src/libraries/System.Text.Json/gen/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -165,4 +165,10 @@
<data name="InaccessibleJsonIncludePropertiesNotSupportedFormat" xml:space="preserve">
<value>The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator.</value>
</data>
<data name="FastPathPolymorphismNotSupportedTitle" xml:space="preserve">
<value>'JsonDerivedTypeAttribute' is not supported in 'JsonSourceGenerationMode.Serialization'.</value>
</data>
<data name="FastPathPolymorphismNotSupportedMessageFormat" xml:space="preserve">
<value>Type '{0}' is annotated with 'JsonDerivedTypeAttribute' which is not supported in 'JsonSourceGenerationMode.Serialization'.</value>
</data>
</root>
10 changes: 10 additions & 0 deletions src/libraries/System.Text.Json/gen/Resources/xlf/Strings.cs.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@
<target state="translated">Duplicitní název typu</target>
<note />
</trans-unit>
<trans-unit id="FastPathPolymorphismNotSupportedMessageFormat">
<source>Type '{0}' is annotated with 'JsonDerivedTypeAttribute' which is not supported in 'JsonSourceGenerationMode.Serialization'.</source>
<target state="new">Type '{0}' is annotated with 'JsonDerivedTypeAttribute' which is not supported in 'JsonSourceGenerationMode.Serialization'.</target>
<note />
</trans-unit>
<trans-unit id="FastPathPolymorphismNotSupportedTitle">
<source>'JsonDerivedTypeAttribute' is not supported in 'JsonSourceGenerationMode.Serialization'.</source>
<target state="new">'JsonDerivedTypeAttribute' is not supported in 'JsonSourceGenerationMode.Serialization'.</target>
<note />
</trans-unit>
<trans-unit id="InaccessibleJsonIncludePropertiesNotSupportedFormat">
<source>The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator.</source>
<target state="translated">Člen {0}.{1} má anotaci od JsonIncludeAttribute, ale není pro zdrojový generátor viditelný.</target>
Expand Down
10 changes: 10 additions & 0 deletions src/libraries/System.Text.Json/gen/Resources/xlf/Strings.de.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@
<target state="translated">Doppelter Typname</target>
<note />
</trans-unit>
<trans-unit id="FastPathPolymorphismNotSupportedMessageFormat">
<source>Type '{0}' is annotated with 'JsonDerivedTypeAttribute' which is not supported in 'JsonSourceGenerationMode.Serialization'.</source>
<target state="new">Type '{0}' is annotated with 'JsonDerivedTypeAttribute' which is not supported in 'JsonSourceGenerationMode.Serialization'.</target>
<note />
</trans-unit>
<trans-unit id="FastPathPolymorphismNotSupportedTitle">
<source>'JsonDerivedTypeAttribute' is not supported in 'JsonSourceGenerationMode.Serialization'.</source>
<target state="new">'JsonDerivedTypeAttribute' is not supported in 'JsonSourceGenerationMode.Serialization'.</target>
<note />
</trans-unit>
<trans-unit id="InaccessibleJsonIncludePropertiesNotSupportedFormat">
<source>The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator.</source>
<target state="translated">Der Member "{0}. {1}" wurde mit dem JsonIncludeAttribute versehen, ist jedoch für den Quellgenerator nicht sichtbar.</target>
Expand Down
10 changes: 10 additions & 0 deletions src/libraries/System.Text.Json/gen/Resources/xlf/Strings.es.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@
<target state="translated">Nombre de tipo duplicado.</target>
<note />
</trans-unit>
<trans-unit id="FastPathPolymorphismNotSupportedMessageFormat">
<source>Type '{0}' is annotated with 'JsonDerivedTypeAttribute' which is not supported in 'JsonSourceGenerationMode.Serialization'.</source>
<target state="new">Type '{0}' is annotated with 'JsonDerivedTypeAttribute' which is not supported in 'JsonSourceGenerationMode.Serialization'.</target>
<note />
</trans-unit>
<trans-unit id="FastPathPolymorphismNotSupportedTitle">
<source>'JsonDerivedTypeAttribute' is not supported in 'JsonSourceGenerationMode.Serialization'.</source>
<target state="new">'JsonDerivedTypeAttribute' is not supported in 'JsonSourceGenerationMode.Serialization'.</target>
<note />
</trans-unit>
<trans-unit id="InaccessibleJsonIncludePropertiesNotSupportedFormat">
<source>The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator.</source>
<target state="translated">El miembro '{0}.{1}' se ha anotado con JsonIncludeAttribute, pero no es visible para el generador de origen.</target>
Expand Down
10 changes: 10 additions & 0 deletions src/libraries/System.Text.Json/gen/Resources/xlf/Strings.fr.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@
<target state="translated">Nom de type dupliqué.</target>
<note />
</trans-unit>
<trans-unit id="FastPathPolymorphismNotSupportedMessageFormat">
<source>Type '{0}' is annotated with 'JsonDerivedTypeAttribute' which is not supported in 'JsonSourceGenerationMode.Serialization'.</source>
<target state="new">Type '{0}' is annotated with 'JsonDerivedTypeAttribute' which is not supported in 'JsonSourceGenerationMode.Serialization'.</target>
<note />
</trans-unit>
<trans-unit id="FastPathPolymorphismNotSupportedTitle">
<source>'JsonDerivedTypeAttribute' is not supported in 'JsonSourceGenerationMode.Serialization'.</source>
<target state="new">'JsonDerivedTypeAttribute' is not supported in 'JsonSourceGenerationMode.Serialization'.</target>
<note />
</trans-unit>
<trans-unit id="InaccessibleJsonIncludePropertiesNotSupportedFormat">
<source>The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator.</source>
<target state="translated">Le membre '{0}.{1}' a été annoté avec JsonIncludeAttribute mais n’est pas visible pour le générateur source.</target>
Expand Down
10 changes: 10 additions & 0 deletions src/libraries/System.Text.Json/gen/Resources/xlf/Strings.it.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@
<target state="translated">Nome di tipo duplicato.</target>
<note />
</trans-unit>
<trans-unit id="FastPathPolymorphismNotSupportedMessageFormat">
<source>Type '{0}' is annotated with 'JsonDerivedTypeAttribute' which is not supported in 'JsonSourceGenerationMode.Serialization'.</source>
<target state="new">Type '{0}' is annotated with 'JsonDerivedTypeAttribute' which is not supported in 'JsonSourceGenerationMode.Serialization'.</target>
<note />
</trans-unit>
<trans-unit id="FastPathPolymorphismNotSupportedTitle">
<source>'JsonDerivedTypeAttribute' is not supported in 'JsonSourceGenerationMode.Serialization'.</source>
<target state="new">'JsonDerivedTypeAttribute' is not supported in 'JsonSourceGenerationMode.Serialization'.</target>
<note />
</trans-unit>
<trans-unit id="InaccessibleJsonIncludePropertiesNotSupportedFormat">
<source>The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator.</source>
<target state="translated">Il membro ' {0}.{1}' è stato annotato con JsonIncludeAttribute ma non è visibile al generatore di origine.</target>
Expand Down
10 changes: 10 additions & 0 deletions src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ja.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@
<target state="translated">重複した種類名。</target>
<note />
</trans-unit>
<trans-unit id="FastPathPolymorphismNotSupportedMessageFormat">
<source>Type '{0}' is annotated with 'JsonDerivedTypeAttribute' which is not supported in 'JsonSourceGenerationMode.Serialization'.</source>
<target state="new">Type '{0}' is annotated with 'JsonDerivedTypeAttribute' which is not supported in 'JsonSourceGenerationMode.Serialization'.</target>
<note />
</trans-unit>
<trans-unit id="FastPathPolymorphismNotSupportedTitle">
<source>'JsonDerivedTypeAttribute' is not supported in 'JsonSourceGenerationMode.Serialization'.</source>
<target state="new">'JsonDerivedTypeAttribute' is not supported in 'JsonSourceGenerationMode.Serialization'.</target>
<note />
</trans-unit>
<trans-unit id="InaccessibleJsonIncludePropertiesNotSupportedFormat">
<source>The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator.</source>
<target state="translated">メンバー '{0}.{1}' には、JsonIncludeAttribute で注釈が付けられていますが、ソース ジェネレーターには表示されません。</target>
Expand Down
10 changes: 10 additions & 0 deletions src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ko.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@
<target state="translated">중복된 형식 이름입니다.</target>
<note />
</trans-unit>
<trans-unit id="FastPathPolymorphismNotSupportedMessageFormat">
<source>Type '{0}' is annotated with 'JsonDerivedTypeAttribute' which is not supported in 'JsonSourceGenerationMode.Serialization'.</source>
<target state="new">Type '{0}' is annotated with 'JsonDerivedTypeAttribute' which is not supported in 'JsonSourceGenerationMode.Serialization'.</target>
<note />
</trans-unit>
<trans-unit id="FastPathPolymorphismNotSupportedTitle">
<source>'JsonDerivedTypeAttribute' is not supported in 'JsonSourceGenerationMode.Serialization'.</source>
<target state="new">'JsonDerivedTypeAttribute' is not supported in 'JsonSourceGenerationMode.Serialization'.</target>
<note />
</trans-unit>
<trans-unit id="InaccessibleJsonIncludePropertiesNotSupportedFormat">
<source>The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator.</source>
<target state="translated">멤버 '{0}.{1}'이(가) JsonIncludeAttribute로 주석 처리되었지만 원본 생성기에는 표시되지 않습니다.</target>
Expand Down
10 changes: 10 additions & 0 deletions src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pl.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@
<target state="translated">Zduplikowana nazwa typu.</target>
<note />
</trans-unit>
<trans-unit id="FastPathPolymorphismNotSupportedMessageFormat">
<source>Type '{0}' is annotated with 'JsonDerivedTypeAttribute' which is not supported in 'JsonSourceGenerationMode.Serialization'.</source>
<target state="new">Type '{0}' is annotated with 'JsonDerivedTypeAttribute' which is not supported in 'JsonSourceGenerationMode.Serialization'.</target>
<note />
</trans-unit>
<trans-unit id="FastPathPolymorphismNotSupportedTitle">
<source>'JsonDerivedTypeAttribute' is not supported in 'JsonSourceGenerationMode.Serialization'.</source>
<target state="new">'JsonDerivedTypeAttribute' is not supported in 'JsonSourceGenerationMode.Serialization'.</target>
<note />
</trans-unit>
<trans-unit id="InaccessibleJsonIncludePropertiesNotSupportedFormat">
<source>The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator.</source>
<target state="translated">Składowa "{0}. {1}" jest adnotowana za pomocą atrybutu JsonIncludeAttribute, ale nie jest widoczna dla generatora źródła.</target>
Expand Down
10 changes: 10 additions & 0 deletions src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pt-BR.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@
<target state="translated">Nome de tipo duplicado.</target>
<note />
</trans-unit>
<trans-unit id="FastPathPolymorphismNotSupportedMessageFormat">
<source>Type '{0}' is annotated with 'JsonDerivedTypeAttribute' which is not supported in 'JsonSourceGenerationMode.Serialization'.</source>
<target state="new">Type '{0}' is annotated with 'JsonDerivedTypeAttribute' which is not supported in 'JsonSourceGenerationMode.Serialization'.</target>
<note />
</trans-unit>
<trans-unit id="FastPathPolymorphismNotSupportedTitle">
<source>'JsonDerivedTypeAttribute' is not supported in 'JsonSourceGenerationMode.Serialization'.</source>
<target state="new">'JsonDerivedTypeAttribute' is not supported in 'JsonSourceGenerationMode.Serialization'.</target>
<note />
</trans-unit>
<trans-unit id="InaccessibleJsonIncludePropertiesNotSupportedFormat">
<source>The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator.</source>
<target state="translated">O membro '{0}.{1}' foi anotado com o JsonIncludeAttribute, mas não é visível para o gerador de origem.</target>
Expand Down
Loading

0 comments on commit b1bd45f

Please sign in to comment.