Skip to content

Commit

Permalink
Fix JSON source gen to work with public context and public types with…
Browse files Browse the repository at this point in the history
… internal properties (dotnet#73622)
  • Loading branch information
krwq authored Aug 11, 2022
1 parent 4893732 commit 14be2a0
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 4 deletions.
10 changes: 10 additions & 0 deletions src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1041,6 +1041,11 @@ private TypeGenerationSpec GetOrAddTypeGenerationSpec(Type type, JsonSourceGener
}

spec = GetPropertyGenerationSpec(propertyInfo, isVirtual, generationMode);
if (!spec.IsPublic && !propertyInfo.PropertyType.IsPublic)
{
continue;
}

CacheMemberHelper(propertyInfo.GetDiagnosticLocation());
}

Expand All @@ -1052,6 +1057,11 @@ private TypeGenerationSpec GetOrAddTypeGenerationSpec(Type type, JsonSourceGener
}

spec = GetPropertyGenerationSpec(fieldInfo, isVirtual: false, generationMode);
if (!spec.IsPublic && !fieldInfo.FieldType.IsPublic)
{
continue;
}

CacheMemberHelper(fieldInfo.GetDiagnosticLocation());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using Microsoft.CodeAnalysis;

namespace System.Text.Json.Reflection
{
internal static class RoslynExtensions
{
public static Type AsType(this ITypeSymbol typeSymbol, MetadataLoadContextInternal metadataLoadContext)
[return: NotNullIfNotNull("typeSymbol")]
public static Type? AsType(this ITypeSymbol? typeSymbol, MetadataLoadContextInternal metadataLoadContext)
{
if (typeSymbol == null)
{
Expand Down
26 changes: 23 additions & 3 deletions src/libraries/System.Text.Json/gen/Reflection/TypeWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ public override string AssemblyQualifiedName
}
}

public override Type BaseType => _typeSymbol.BaseType!.AsType(_metadataLoadContext);
public override Type BaseType => _typeSymbol.BaseType.AsType(_metadataLoadContext);

public override Type DeclaringType => _typeSymbol.ContainingType?.ConstructedFrom.AsType(_metadataLoadContext);

Expand Down Expand Up @@ -499,9 +499,29 @@ protected override TypeAttributes GetAttributeFlagsImpl()
_typeAttributes |= TypeAttributes.Interface;
}

if (_typeSymbol.ContainingType != null && _typeSymbol.DeclaredAccessibility == Accessibility.Private)
bool isNested = _typeSymbol.ContainingType != null;

switch (_typeSymbol.DeclaredAccessibility)
{
_typeAttributes |= TypeAttributes.NestedPrivate;
case Accessibility.NotApplicable:
case Accessibility.Private:
_typeAttributes |= isNested ? TypeAttributes.NestedPrivate : TypeAttributes.NotPublic;
break;
case Accessibility.ProtectedAndInternal:
_typeAttributes |= isNested ? TypeAttributes.NestedFamANDAssem : TypeAttributes.NotPublic;
break;
case Accessibility.Protected:
_typeAttributes |= isNested ? TypeAttributes.NestedFamily : TypeAttributes.NotPublic;
break;
case Accessibility.Internal:
_typeAttributes |= isNested ? TypeAttributes.NestedAssembly : TypeAttributes.NotPublic;
break;
case Accessibility.ProtectedOrInternal:
_typeAttributes |= isNested ? TypeAttributes.NestedFamORAssem : TypeAttributes.NotPublic;
break;
case Accessibility.Public:
_typeAttributes |= isNested ? TypeAttributes.NestedPublic : TypeAttributes.Public;
break;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@ public JsonTypeInfo<JsonMessage> JsonMessage
internal partial class DictionaryTypeContext : JsonSerializerContext { }

[JsonSerializable(typeof(JsonMessage))]
[JsonSerializable(typeof(PublicClassWithDifferentAccessibilitiesProperties))]
[JsonSerializable(typeof(JsonConverter))]
[JsonSerializable(typeof(JsonSerializerOptions))]
public partial class PublicContext : JsonSerializerContext { }

[JsonSerializable(typeof(JsonMessage))]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Reflection;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
using System.Text.Json.Serialization.Tests;
using System.Threading.Tasks;
using Xunit;
Expand Down Expand Up @@ -326,6 +327,66 @@ public override async Task JsonIgnoreCondition_WhenWritingNull_OnValueType_Fail_
await Assert.ThrowsAsync<InvalidOperationException>(async () => await Serializer.SerializeWrapper(Activator.CreateInstance(type), type));
}

[Fact]
public static void PublicContexAndTestClassWithPropertiesWithDifferentAccesibilities()
{
JsonSerializerOptions options = new()
{
IncludeFields = true,
};

options.AddContext<PublicContext>();

PublicClassWithDifferentAccessibilitiesProperties obj = new()
{
PublicProperty = new(),
PublicField = new(),
};

string json = JsonSerializer.Serialize(obj, options);
Assert.Equal("""{"PublicProperty":{},"PublicField":{}}""", json);

var deserialized = JsonSerializer.Deserialize<PublicClassWithDifferentAccessibilitiesProperties>(json, options);
Assert.NotNull(deserialized.PublicProperty);
Assert.NotNull(deserialized.PublicField);

json = "{}";
deserialized = JsonSerializer.Deserialize<PublicClassWithDifferentAccessibilitiesProperties>(json, options);
Assert.Null(deserialized.PublicProperty);
Assert.Null(deserialized.PublicField);
}

[Fact]
public static void PublicContexAndJsonConverter()
{
JsonConverter obj = JsonMetadataServices.BooleanConverter;

string json = JsonSerializer.Serialize(obj, PublicContext.Default.Options);
Assert.Equal("{}", json);

Assert.Throws<NotSupportedException>(() => JsonSerializer.Deserialize<JsonConverter>(json, PublicContext.Default.Options));
}

[Fact]
public static void PublicContexAndJsonSerializerOptions()
{
JsonSerializerOptions obj = new()
{
DefaultBufferSize = 123,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
IncludeFields = true,
};

string json = JsonSerializer.Serialize(obj, PublicContext.Default.Options);

JsonSerializerOptions deserialized = JsonSerializer.Deserialize<JsonSerializerOptions>(json, PublicContext.Default.Options);
Assert.Equal(obj.DefaultBufferSize, deserialized.DefaultBufferSize);
Assert.Equal(obj.DefaultIgnoreCondition, deserialized.DefaultIgnoreCondition);
Assert.Equal(obj.IncludeFields, deserialized.IncludeFields);
Assert.Equal(obj.IgnoreReadOnlyFields, deserialized.IgnoreReadOnlyFields);
Assert.Equal(obj.MaxDepth, deserialized.MaxDepth);
}

[JsonSerializable(typeof(ClassWithNewSlotField))]
[JsonSerializable(typeof(int))]
[JsonSerializable(typeof(object))]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,4 +226,53 @@ public class MyNestedGenericNestedGenericClass<T2>
}
}
}

public class PublicClassWithDifferentAccessibilitiesProperties
{
public PublicTestClass PublicProperty { get; set; }
internal PublicTestClass.InternalNestedClass InternalProperty1 { get; set; }
protected ProtectedClass ProtectedProperty1 { get; set; }
protected ProtectedInternalClass ProtectedProperty2 { get; set; }
internal InternalTestClass InternalProperty2 { get; set; }
internal InternalTestClass.PublicClass InternalProperty3 { get; set; }
internal InternalTestClass.ProtectedInternalClass InternalProperty4 { get; set; }
private InternalTestClass PrivateProperty1 { get; set; }
private PrivateClass PrivateProperty2 { get; set; }
private PrivateClass2 PrivateProperty3 { get; set; }
PrivateClass2 PrivateProperty4 { get; set; }
private PrivateProtectedClass PrivateProperty5 { get; set; }

public PublicTestClass PublicField;

#pragma warning disable CS0414 // The field ... is assigned but its value is never used.
internal PublicTestClass.InternalNestedClass InternalField1 = null;
protected ProtectedClass ProtectedField1 = null;
protected ProtectedInternalClass ProtectedField2 = null;
internal InternalTestClass InternalField2 = null;
internal InternalTestClass.PublicClass InternalField3 = null;
internal InternalTestClass.ProtectedInternalClass InternalField4 = null;
private InternalTestClass PrivateField1 = null;
private PrivateClass PrivateField2 = null;
private PrivateClass2 PrivateField3 = null;
PrivateClass2 PrivateField4 = null;
private PrivateProtectedClass PrivateField5 = null;
#pragma warning restore

private class PrivateClass { }
protected class ProtectedClass { }
protected internal class ProtectedInternalClass { }
private protected class PrivateProtectedClass { }
class PrivateClass2 { }
}

internal class InternalTestClass
{
public class PublicClass { }
protected internal class ProtectedInternalClass { }
}

public class PublicTestClass
{
internal class InternalNestedClass { }
}
}

0 comments on commit 14be2a0

Please sign in to comment.