From 895eb99d4987654cfb18e922a00c428678394bab Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 7 Sep 2021 19:50:45 -0600 Subject: [PATCH] fix ValueTuple source generation support (#58723) Co-authored-by: Eirik Tsarpalis --- .../System.Text.Json/gen/Reflection/TypeWrapper.cs | 4 +++- .../ContextClasses.cs | 3 +++ .../MetadataAndSerializationContextTests.cs | 2 ++ .../MetadataContextTests.cs | 6 +++++- .../MixedModeContextTests.cs | 3 +++ .../RealWorldContextTests.cs | 25 ++++++++++++++++++++++ .../SerializationContextTests.cs | 7 +++++- 7 files changed, 47 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Text.Json/gen/Reflection/TypeWrapper.cs b/src/libraries/System.Text.Json/gen/Reflection/TypeWrapper.cs index 50d76bf..71ea983 100644 --- a/src/libraries/System.Text.Json/gen/Reflection/TypeWrapper.cs +++ b/src/libraries/System.Text.Json/gen/Reflection/TypeWrapper.cs @@ -311,7 +311,9 @@ namespace System.Text.Json.Reflection // we want a static field and this is not static (BindingFlags.Static & bindingAttr) != 0 && !fieldSymbol.IsStatic || // we want an instance field and this is static or a constant - (BindingFlags.Instance & bindingAttr) != 0 && (fieldSymbol.IsStatic || fieldSymbol.IsConst)) + (BindingFlags.Instance & bindingAttr) != 0 && (fieldSymbol.IsStatic || fieldSymbol.IsConst) || + // symbol represents an explicitly named tuple element + fieldSymbol.IsExplicitlyNamedTupleElement) { continue; } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/ContextClasses.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/ContextClasses.cs index 47bfe5a..f78c0a4 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/ContextClasses.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/ContextClasses.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.Metadata; @@ -10,6 +11,7 @@ namespace System.Text.Json.SourceGeneration.Tests public interface ITestContext { public JsonSourceGenerationMode JsonSourceGenerationMode { get; } + public bool IsIncludeFieldsEnabled => GetType().GetCustomAttribute()?.IncludeFields ?? false; public JsonTypeInfo Location { get; } public JsonTypeInfo NumberTypes { get; } @@ -30,6 +32,7 @@ namespace System.Text.Json.SourceGeneration.Tests public JsonTypeInfo MyNestedNestedClass { get; } public JsonTypeInfo ObjectArray { get; } public JsonTypeInfo String { get; } + public JsonTypeInfo<(string Label1, int Label2, bool)> ValueTupleStringInt32Boolean { get; } public JsonTypeInfo ClassWithEnumAndNullable { get; } public JsonTypeInfo ClassWithCustomConverter { get; } public JsonTypeInfo StructWithCustomConverter { get; } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/MetadataAndSerializationContextTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/MetadataAndSerializationContextTests.cs index 201ef07..a74dd32 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/MetadataAndSerializationContextTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/MetadataAndSerializationContextTests.cs @@ -26,6 +26,7 @@ namespace System.Text.Json.SourceGeneration.Tests [JsonSerializable(typeof(RealWorldContextTests.MyNestedClass.MyNestedNestedClass))] [JsonSerializable(typeof(object[]))] [JsonSerializable(typeof(string))] + [JsonSerializable(typeof((string Label1, int Label2, bool)))] [JsonSerializable(typeof(RealWorldContextTests.ClassWithEnumAndNullable))] [JsonSerializable(typeof(ClassWithCustomConverter))] [JsonSerializable(typeof(StructWithCustomConverter))] @@ -69,6 +70,7 @@ namespace System.Text.Json.SourceGeneration.Tests Assert.Null(MetadataAndSerializationContext.Default.ObjectArray.Serialize); Assert.Null(MetadataAndSerializationContext.Default.SampleEnum.Serialize); Assert.Null(MetadataAndSerializationContext.Default.String.Serialize); + Assert.NotNull(MetadataAndSerializationContext.Default.ValueTupleStringInt32Boolean.Serialize); Assert.NotNull(MetadataAndSerializationContext.Default.ClassWithEnumAndNullable.Serialize); Assert.NotNull(MetadataAndSerializationContext.Default.ClassWithCustomConverter); Assert.NotNull(MetadataAndSerializationContext.Default.StructWithCustomConverter); diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/MetadataContextTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/MetadataContextTests.cs index 945082d..d9fb766 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/MetadataContextTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/MetadataContextTests.cs @@ -25,6 +25,7 @@ namespace System.Text.Json.SourceGeneration.Tests [JsonSerializable(typeof(RealWorldContextTests.MyNestedClass.MyNestedNestedClass), GenerationMode = JsonSourceGenerationMode.Metadata)] [JsonSerializable(typeof(object[]), GenerationMode = JsonSourceGenerationMode.Metadata)] [JsonSerializable(typeof(string), GenerationMode = JsonSourceGenerationMode.Metadata)] + [JsonSerializable(typeof((string Label1, int Label2, bool)), GenerationMode = JsonSourceGenerationMode.Metadata)] [JsonSerializable(typeof(RealWorldContextTests.ClassWithEnumAndNullable), GenerationMode = JsonSourceGenerationMode.Metadata)] [JsonSerializable(typeof(ClassWithCustomConverter), GenerationMode = JsonSourceGenerationMode.Metadata)] [JsonSerializable(typeof(StructWithCustomConverter), GenerationMode = JsonSourceGenerationMode.Metadata)] @@ -66,6 +67,7 @@ namespace System.Text.Json.SourceGeneration.Tests Assert.Null(MetadataWithPerTypeAttributeContext.Default.ObjectArray.Serialize); Assert.Null(MetadataWithPerTypeAttributeContext.Default.SampleEnum.Serialize); Assert.Null(MetadataWithPerTypeAttributeContext.Default.String.Serialize); + Assert.Null(MetadataWithPerTypeAttributeContext.Default.ValueTupleStringInt32Boolean.Serialize); Assert.Null(MetadataWithPerTypeAttributeContext.Default.ClassWithEnumAndNullable.Serialize); Assert.Null(MetadataWithPerTypeAttributeContext.Default.ClassWithCustomConverter.Serialize); Assert.Null(MetadataWithPerTypeAttributeContext.Default.StructWithCustomConverter.Serialize); @@ -80,7 +82,7 @@ namespace System.Text.Json.SourceGeneration.Tests } } - [JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Metadata)] + [JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Metadata, IncludeFields = true)] [JsonSerializable(typeof(Location))] [JsonSerializable(typeof(RepeatedTypes.Location), TypeInfoPropertyName = "RepeatedLocation")] [JsonSerializable(typeof(NumberTypes))] @@ -100,6 +102,7 @@ namespace System.Text.Json.SourceGeneration.Tests [JsonSerializable(typeof(RealWorldContextTests.MyNestedClass.MyNestedNestedClass))] [JsonSerializable(typeof(object[]))] [JsonSerializable(typeof(string))] + [JsonSerializable(typeof((string Label1, int Label2, bool)))] [JsonSerializable(typeof(RealWorldContextTests.ClassWithEnumAndNullable))] [JsonSerializable(typeof(ClassWithCustomConverter))] [JsonSerializable(typeof(StructWithCustomConverter))] @@ -164,6 +167,7 @@ namespace System.Text.Json.SourceGeneration.Tests Assert.Null(MetadataContext.Default.ObjectArray.Serialize); Assert.Null(MetadataContext.Default.SampleEnum.Serialize); Assert.Null(MetadataContext.Default.String.Serialize); + Assert.Null(MetadataContext.Default.ValueTupleStringInt32Boolean.Serialize); Assert.Null(MetadataContext.Default.ClassWithEnumAndNullable.Serialize); Assert.Null(MetadataContext.Default.ClassWithCustomConverter.Serialize); Assert.Null(MetadataContext.Default.StructWithCustomConverter.Serialize); diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/MixedModeContextTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/MixedModeContextTests.cs index ae0c289..82b8288 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/MixedModeContextTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/MixedModeContextTests.cs @@ -6,6 +6,7 @@ using Xunit; namespace System.Text.Json.SourceGeneration.Tests { + [JsonSourceGenerationOptions(IncludeFields = true)] [JsonSerializable(typeof(Location), GenerationMode = JsonSourceGenerationMode.Metadata)] [JsonSerializable(typeof(RepeatedTypes.Location), TypeInfoPropertyName = "RepeatedLocation", GenerationMode = JsonSourceGenerationMode.Serialization)] [JsonSerializable(typeof(NumberTypes), GenerationMode = JsonSourceGenerationMode.Metadata)] @@ -25,6 +26,7 @@ namespace System.Text.Json.SourceGeneration.Tests [JsonSerializable(typeof(RealWorldContextTests.MyNestedClass.MyNestedNestedClass), GenerationMode = JsonSourceGenerationMode.Serialization)] [JsonSerializable(typeof(object[]), GenerationMode = JsonSourceGenerationMode.Metadata)] [JsonSerializable(typeof(string), GenerationMode = JsonSourceGenerationMode.Metadata | JsonSourceGenerationMode.Serialization)] + [JsonSerializable(typeof((string Label1, int Label2, bool)), GenerationMode = JsonSourceGenerationMode.Metadata | JsonSourceGenerationMode.Serialization)] [JsonSerializable(typeof(RealWorldContextTests.ClassWithEnumAndNullable), GenerationMode = JsonSourceGenerationMode.Metadata | JsonSourceGenerationMode.Serialization)] [JsonSerializable(typeof(ClassWithCustomConverter), GenerationMode = JsonSourceGenerationMode.Metadata | JsonSourceGenerationMode.Serialization)] [JsonSerializable(typeof(StructWithCustomConverter), GenerationMode = JsonSourceGenerationMode.Metadata | JsonSourceGenerationMode.Serialization)] @@ -67,6 +69,7 @@ namespace System.Text.Json.SourceGeneration.Tests Assert.Null(MixedModeContext.Default.ObjectArray.Serialize); Assert.Null(MixedModeContext.Default.SampleEnum.Serialize); Assert.Null(MixedModeContext.Default.String.Serialize); + Assert.NotNull(MixedModeContext.Default.ValueTupleStringInt32Boolean.Serialize); Assert.NotNull(MixedModeContext.Default.ClassWithEnumAndNullable.Serialize); Assert.Null(MixedModeContext.Default.ClassWithCustomConverter.Serialize); Assert.Null(MixedModeContext.Default.StructWithCustomConverter.Serialize); diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/RealWorldContextTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/RealWorldContextTests.cs index fef2ddd..d10300c 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/RealWorldContextTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/RealWorldContextTests.cs @@ -111,6 +111,31 @@ namespace System.Text.Json.SourceGeneration.Tests } [Fact] + public virtual void RoundTripValueTuple() + { + bool isIncludeFieldsEnabled = DefaultContext.IsIncludeFieldsEnabled; + + var tuple = (Label1: "string", Label2: 42, true); + string expectedJson = isIncludeFieldsEnabled + ? "{\"Item1\":\"string\",\"Item2\":42,\"Item3\":true}" + : "{}"; + + string json = JsonSerializer.Serialize(tuple, DefaultContext.ValueTupleStringInt32Boolean); + Assert.Equal(expectedJson, json); + + if (DefaultContext.JsonSourceGenerationMode == JsonSourceGenerationMode.Serialization) + { + // Deserialization not supported in fast path serialization only mode + Assert.Throws(() => JsonSerializer.Deserialize(json, DefaultContext.ValueTupleStringInt32Boolean)); + } + else + { + var deserializedTuple = JsonSerializer.Deserialize(json, DefaultContext.ValueTupleStringInt32Boolean); + Assert.Equal(isIncludeFieldsEnabled ? tuple : default, deserializedTuple); + } + } + + [Fact] public virtual void RoundTripWithCustomConverter_Class() { const string Json = "{\"MyInt\":142}"; diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/SerializationContextTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/SerializationContextTests.cs index 501d671..639f380 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/SerializationContextTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/SerializationContextTests.cs @@ -26,6 +26,7 @@ namespace System.Text.Json.SourceGeneration.Tests [JsonSerializable(typeof(RealWorldContextTests.MyNestedClass.MyNestedNestedClass))] [JsonSerializable(typeof(object[]))] [JsonSerializable(typeof(string))] + [JsonSerializable(typeof((string Label1, int Label2, bool)))] [JsonSerializable(typeof(RealWorldContextTests.ClassWithEnumAndNullable))] [JsonSerializable(typeof(ClassWithCustomConverter))] [JsonSerializable(typeof(StructWithCustomConverter))] @@ -61,6 +62,7 @@ namespace System.Text.Json.SourceGeneration.Tests [JsonSerializable(typeof(RealWorldContextTests.MyNestedClass.MyNestedNestedClass), GenerationMode = JsonSourceGenerationMode.Serialization)] [JsonSerializable(typeof(object[]), GenerationMode = JsonSourceGenerationMode.Serialization)] [JsonSerializable(typeof(string), GenerationMode = JsonSourceGenerationMode.Serialization)] + [JsonSerializable(typeof((string Label1, int Label2, bool)), GenerationMode = JsonSourceGenerationMode.Serialization)] [JsonSerializable(typeof(RealWorldContextTests.ClassWithEnumAndNullable), GenerationMode = JsonSourceGenerationMode.Serialization)] [JsonSerializable(typeof(ClassWithCustomConverter), GenerationMode = JsonSourceGenerationMode.Serialization)] [JsonSerializable(typeof(StructWithCustomConverter), GenerationMode = JsonSourceGenerationMode.Serialization)] @@ -77,7 +79,7 @@ namespace System.Text.Json.SourceGeneration.Tests public JsonSourceGenerationMode JsonSourceGenerationMode => JsonSourceGenerationMode.Serialization; } - [JsonSourceGenerationOptions(PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase)] + [JsonSourceGenerationOptions(PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase, IncludeFields = true)] [JsonSerializable(typeof(Location), GenerationMode = JsonSourceGenerationMode.Serialization)] [JsonSerializable(typeof(RepeatedTypes.Location), GenerationMode = JsonSourceGenerationMode.Serialization, TypeInfoPropertyName = "RepeatedLocation")] [JsonSerializable(typeof(NumberTypes), GenerationMode = JsonSourceGenerationMode.Serialization)] @@ -97,6 +99,7 @@ namespace System.Text.Json.SourceGeneration.Tests [JsonSerializable(typeof(RealWorldContextTests.MyNestedClass.MyNestedNestedClass), GenerationMode = JsonSourceGenerationMode.Serialization)] [JsonSerializable(typeof(object[]), GenerationMode = JsonSourceGenerationMode.Serialization)] [JsonSerializable(typeof(string), GenerationMode = JsonSourceGenerationMode.Serialization)] + [JsonSerializable(typeof((string Label1, int Label2, bool)), GenerationMode = JsonSourceGenerationMode.Serialization)] [JsonSerializable(typeof(RealWorldContextTests.ClassWithEnumAndNullable), GenerationMode = JsonSourceGenerationMode.Serialization)] [JsonSerializable(typeof(ClassWithCustomConverter), GenerationMode = JsonSourceGenerationMode.Serialization)] [JsonSerializable(typeof(StructWithCustomConverter), GenerationMode = JsonSourceGenerationMode.Serialization)] @@ -144,6 +147,7 @@ namespace System.Text.Json.SourceGeneration.Tests Assert.NotNull(SerializationContext.Default.MyNestedNestedClass.Serialize); Assert.Null(SerializationContext.Default.ObjectArray.Serialize); Assert.Null(SerializationContext.Default.String.Serialize); + Assert.NotNull(SerializationContext.Default.ValueTupleStringInt32Boolean.Serialize); Assert.NotNull(SerializationContext.Default.ClassWithEnumAndNullable.Serialize); Assert.Null(SerializationContext.Default.ClassWithCustomConverter.Serialize); Assert.Null(SerializationContext.Default.StructWithCustomConverter.Serialize); @@ -411,6 +415,7 @@ namespace System.Text.Json.SourceGeneration.Tests Assert.Null(SerializationWithPerTypeAttributeContext.Default.ObjectArray.Serialize); Assert.Null(SerializationWithPerTypeAttributeContext.Default.SampleEnum.Serialize); Assert.Null(SerializationWithPerTypeAttributeContext.Default.String.Serialize); + Assert.NotNull(SerializationWithPerTypeAttributeContext.Default.ValueTupleStringInt32Boolean.Serialize); Assert.NotNull(SerializationWithPerTypeAttributeContext.Default.ClassWithEnumAndNullable.Serialize); Assert.Null(SerializationWithPerTypeAttributeContext.Default.ClassWithCustomConverter.Serialize); Assert.Null(SerializationWithPerTypeAttributeContext.Default.StructWithCustomConverter.Serialize); -- 2.7.4