Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add linker annotations for System.Text.Json #38595

Merged
merged 11 commits into from
Jul 7, 2020
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,12 @@ namespace System.Diagnostics.CodeAnalysis
AttributeTargets.Field | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter |
AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Method,
Inherited = false)]
public sealed class DynamicallyAccessedMembersAttribute : Attribute
#if SYSTEM_PRIVATE_CORELIB
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think I understand why you need this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand why you need it now. I'm not sure I agree with what we are doing here to be honest, but I'm fine if that is the direction we are going to take.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that is the direction we've decided to take. See #36656 (comment)

The other attributes in this folder already have it:

#if SYSTEM_PRIVATE_CORELIB
public
#else
internal
#endif
sealed class DynamicDependencyAttribute : Attribute

#if INTERNAL_NULLABLE_ATTRIBUTES
internal
#else
public
#endif
sealed class AllowNullAttribute : Attribute { }

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, honestly I don't fully agree with this approach (as opposed to having them available down level) since we probably want to allow library developers that target netstandard or < .NET5.0 to be able to annotate their libraries as well, specially if these will be libraries used for blazor wasm. Given the attribute implementation is fully netstandard2.0 compatible, I would opt instead for having compatibility packs (similar to what we did with AsyncInterfaces) for shipping the attributes down level so that we a) don't have to compile these attributes internally on a bunch of libraries and b) allow third party library writters to consume them. I don't want to push to much on doing this but just wanted to share my opinion 😄 cc: @stephentoub

public
#else
internal
#endif
sealed class DynamicallyAccessedMembersAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="DynamicallyAccessedMembersAttribute"/> class
Expand Down
30 changes: 30 additions & 0 deletions src/libraries/System.Text.Json/ref/System.Text.Json.cs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,29 @@ public partial struct JsonReaderState
}
public static partial class JsonSerializer
{
#if NETCOREAPP
private const System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes MembersAccessedOnRead = System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties;
private const System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes MembersAccessedOnWrite = System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties;
public static object? Deserialize(System.ReadOnlySpan<byte> utf8Json, [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(MembersAccessedOnRead)] System.Type returnType, System.Text.Json.JsonSerializerOptions? options = null) { throw null; }
public static object? Deserialize(string json, [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(MembersAccessedOnRead)] System.Type returnType, System.Text.Json.JsonSerializerOptions? options = null) { throw null; }
public static object? Deserialize(ref System.Text.Json.Utf8JsonReader reader, [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(MembersAccessedOnRead)] System.Type returnType, System.Text.Json.JsonSerializerOptions? options = null) { throw null; }
public static System.Threading.Tasks.ValueTask<object?> DeserializeAsync(System.IO.Stream utf8Json, [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(MembersAccessedOnRead)] System.Type returnType, System.Text.Json.JsonSerializerOptions? options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public static System.Threading.Tasks.ValueTask<TValue> DeserializeAsync<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(MembersAccessedOnRead)] TValue>(System.IO.Stream utf8Json, System.Text.Json.JsonSerializerOptions? options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
[return: System.Diagnostics.CodeAnalysis.MaybeNull]
public static TValue Deserialize<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(MembersAccessedOnRead)] TValue>(System.ReadOnlySpan<byte> utf8Json, System.Text.Json.JsonSerializerOptions? options = null) { throw null; }
[return: System.Diagnostics.CodeAnalysis.MaybeNull]
public static TValue Deserialize<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(MembersAccessedOnRead)] TValue>(string json, System.Text.Json.JsonSerializerOptions? options = null) { throw null; }
[return: System.Diagnostics.CodeAnalysis.MaybeNull]
public static TValue Deserialize<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(MembersAccessedOnRead)] TValue>(ref System.Text.Json.Utf8JsonReader reader, System.Text.Json.JsonSerializerOptions? options = null) { throw null; }
public static string Serialize(object? value, [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(MembersAccessedOnWrite)] System.Type inputType, System.Text.Json.JsonSerializerOptions? options = null) { throw null; }
public static void Serialize(System.Text.Json.Utf8JsonWriter writer, object? value, [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(MembersAccessedOnWrite)] System.Type inputType, System.Text.Json.JsonSerializerOptions? options = null) { }
public static System.Threading.Tasks.Task SerializeAsync(System.IO.Stream utf8Json, object? value, [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(MembersAccessedOnWrite)] System.Type inputType, System.Text.Json.JsonSerializerOptions? options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public static System.Threading.Tasks.Task SerializeAsync<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(MembersAccessedOnWrite)] TValue>(System.IO.Stream utf8Json, TValue value, System.Text.Json.JsonSerializerOptions? options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public static byte[] SerializeToUtf8Bytes(object? value, [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(MembersAccessedOnWrite)] System.Type inputType, System.Text.Json.JsonSerializerOptions? options = null) { throw null; }
public static byte[] SerializeToUtf8Bytes<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(MembersAccessedOnWrite)] TValue>(TValue value, System.Text.Json.JsonSerializerOptions? options = null) { throw null; }
public static void Serialize<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(MembersAccessedOnWrite)] TValue>(System.Text.Json.Utf8JsonWriter writer, TValue value, System.Text.Json.JsonSerializerOptions? options = null) { }
public static string Serialize<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(MembersAccessedOnWrite)] TValue>(TValue value, System.Text.Json.JsonSerializerOptions? options = null) { throw null; }
#else
public static object? Deserialize(System.ReadOnlySpan<byte> utf8Json, System.Type returnType, System.Text.Json.JsonSerializerOptions? options = null) { throw null; }
public static object? Deserialize(string json, System.Type returnType, System.Text.Json.JsonSerializerOptions? options = null) { throw null; }
public static object? Deserialize(ref System.Text.Json.Utf8JsonReader reader, System.Type returnType, System.Text.Json.JsonSerializerOptions? options = null) { throw null; }
Expand All @@ -204,6 +227,7 @@ public static void Serialize(System.Text.Json.Utf8JsonWriter writer, object? val
public static byte[] SerializeToUtf8Bytes<TValue>(TValue value, System.Text.Json.JsonSerializerOptions? options = null) { throw null; }
public static void Serialize<TValue>(System.Text.Json.Utf8JsonWriter writer, TValue value, System.Text.Json.JsonSerializerOptions? options = null) { }
public static string Serialize<TValue>(TValue value, System.Text.Json.JsonSerializerOptions? options = null) { throw null; }
#endif
}
public sealed partial class JsonSerializerOptions
{
Expand Down Expand Up @@ -483,8 +507,14 @@ internal JsonConverter() { }
public partial class JsonConverterAttribute : System.Text.Json.Serialization.JsonAttribute
{
protected JsonConverterAttribute() { }
#if NETCOREAPP
public JsonConverterAttribute([System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] System.Type converterType) { }
[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]
public System.Type? ConverterType { get { throw null; } }
#else
public JsonConverterAttribute(System.Type converterType) { }
public System.Type? ConverterType { get { throw null; } }
#endif
public virtual System.Text.Json.Serialization.JsonConverter? CreateConverter(System.Type typeToConvert) { throw null; }
}
public abstract partial class JsonConverterFactory : System.Text.Json.Serialization.JsonConverter
Expand Down
1 change: 1 addition & 0 deletions src/libraries/System.Text.Json/src/System.Text.Json.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' != '$(NetCoreAppCurrent)'">
<Compile Include="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\DynamicDependencyAttribute.cs" />
<Compile Include="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\DynamicallyAccessedMembersAttribute.cs" />
layomia marked this conversation as resolved.
Show resolved Hide resolved
<Compile Include="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\DynamicallyAccessedMemberTypes.cs" />
</ItemGroup>
<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Diagnostics.CodeAnalysis;

namespace System.Text.Json.Serialization
{
/// <summary>
Expand All @@ -21,7 +23,7 @@ public class JsonConverterAttribute : JsonAttribute
/// Initializes a new instance of <see cref="JsonConverterAttribute"/> with the specified converter type.
/// </summary>
/// <param name="converterType">The type of the converter.</param>
public JsonConverterAttribute(Type converterType)
public JsonConverterAttribute([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type converterType)
layomia marked this conversation as resolved.
Show resolved Hide resolved
{
ConverterType = converterType;
}
Expand All @@ -34,6 +36,7 @@ protected JsonConverterAttribute() { }
/// <summary>
/// The type of the converter to create, or null if <see cref="CreateConverter(Type)"/> should be used to obtain the converter.
/// </summary>
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]
public Type? ConverterType { get; private set; }

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;

namespace System.Text.Json.Serialization.Converters
Expand All @@ -25,23 +24,6 @@ public override bool CanConvert(Type typeToConvert)
return typeof(IEnumerable).IsAssignableFrom(typeToConvert);
}

[DynamicDependency("#ctor", typeof(ArrayConverter<,>))]
[DynamicDependency("#ctor", typeof(ConcurrentQueueOfTConverter<,>))]
[DynamicDependency("#ctor", typeof(ConcurrentStackOfTConverter<,>))]
[DynamicDependency("#ctor", typeof(DictionaryOfStringTValueConverter<,>))]
[DynamicDependency("#ctor", typeof(ICollectionOfTConverter<,>))]
[DynamicDependency("#ctor", typeof(IDictionaryOfStringTValueConverter<,>))]
[DynamicDependency("#ctor", typeof(IEnumerableOfTConverter<,>))]
[DynamicDependency("#ctor", typeof(IEnumerableWithAddMethodConverter<>))]
[DynamicDependency("#ctor", typeof(IListConverter<>))]
[DynamicDependency("#ctor", typeof(IListOfTConverter<,>))]
[DynamicDependency("#ctor", typeof(ImmutableDictionaryOfStringTValueConverter<,>))]
[DynamicDependency("#ctor", typeof(ImmutableEnumerableOfTConverter<,>))]
[DynamicDependency("#ctor", typeof(IReadOnlyDictionaryOfStringTValueConverter<,>))]
layomia marked this conversation as resolved.
Show resolved Hide resolved
[DynamicDependency("#ctor", typeof(ISetOfTConverter<,>))]
[DynamicDependency("#ctor", typeof(ListOfTConverter<,>))]
[DynamicDependency("#ctor", typeof(QueueOfTConverter<,>))]
[DynamicDependency("#ctor", typeof(StackOfTConverter<,>))]
public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
{
Type converterType = null!;
Expand Down
Loading