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

Should we remove DynamicallyAccessedMembers attributes on JsonSerializer? #52268

Closed
eerhardt opened this issue May 4, 2021 · 6 comments · Fixed by #53235
Closed

Should we remove DynamicallyAccessedMembers attributes on JsonSerializer? #52268

eerhardt opened this issue May 4, 2021 · 6 comments · Fixed by #53235
Labels
area-System.Text.Json untriaged New issue has not been triaged by the area owner

Comments

@eerhardt
Copy link
Member

eerhardt commented May 4, 2021

In 5.0, we annotated the JsonSerializer APIs with DynamicallyAccessedMembers attributes in #38595.

[RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)]
public static TValue? Deserialize<[DynamicallyAccessedMembers(JsonHelpers.MembersAccessedOnRead)] TValue>(string json, JsonSerializerOptions? options = null)

[RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)]
public static string Serialize<[DynamicallyAccessedMembers(MembersAccessedOnWrite)] TValue>(TValue value, JsonSerializerOptions? options = null)

In 6.0, we resolved all the ILLink warnings in System.Text.Json in #51886, which caused us to also add the RequiresUnreferencedCode attributes. This is because the trim annotations can't model everything that needs to be preserved to make these APIs trim compatible. For example, see dotnet/linker#1087.

Having both sets of attributes on these APIs isn't really ideal. The DynamicallyAccessedMembers attributes will only preserve members on the top-level type. So having the DynamicallyAccessedMembers gives a false sense of hope that this API will work with trimming, when in reality it won't.

The small benefit it does provide is in the case where the user is not serializing a graph, but just a class with primitive properties. However, even in this case, we'd like the user to move to use the source generator instead. So keeping these attributes for this tiny case doesn't seem to outweigh the benefit of the encouragement to move to using the source generator.

We also didn't annotate the DataContractSerializer and XmlSerializer APIs like this. We just marked the unsafe APIs with RequiresUnreferencedCode.

However, if we have plans for making the non-source generation Json serializer APIs work with trimming in 6.0, it might not be worth the effort of removing these attributes now, just to add them back in the near future.

cc @vitek-karas @agocke @layomia @steveharter

@dotnet-issue-labeler dotnet-issue-labeler bot added area-System.Text.Json untriaged New issue has not been triaged by the area owner labels May 4, 2021
@ghost
Copy link

ghost commented May 4, 2021

Tagging subscribers to this area: @eiriktsarpalis, @layomia
See info in area-owners.md if you want to be subscribed.

Issue Details

In 5.0, we annotated the JsonSerializer APIs with DynamicallyAccessedMembers attributes in #38595.

[RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)]
public static TValue? Deserialize<[DynamicallyAccessedMembers(JsonHelpers.MembersAccessedOnRead)] TValue>(string json, JsonSerializerOptions? options = null)

[RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)]
public static string Serialize<[DynamicallyAccessedMembers(MembersAccessedOnWrite)] TValue>(TValue value, JsonSerializerOptions? options = null)

In 6.0, we resolved all the ILLink warnings in System.Text.Json in #51886, which caused us to also add the RequiresUnreferencedCode attributes. This is because the trim annotations can't model everything that needs to be preserved to make these APIs trim compatible. For example, see dotnet/linker#1087.

Having both sets of attributes on these APIs isn't really ideal. The DynamicallyAccessedMembers attributes will only preserve members on the top-level type. So having the DynamicallyAccessedMembers gives a false sense of hope that this API will work with trimming, when in reality it won't.

The small benefit it does provide is in the case where the user is not serializing a graph, but just a class with primitive properties. However, even in this case, we'd like the user to move to use the source generator instead. So keeping these attributes for this tiny case doesn't seem to outweigh the benefit of the encouragement to move to using the source generator.

We also didn't annotate the DataContractSerializer and XmlSerializer APIs like this. We just marked the unsafe APIs with RequiresUnreferencedCode.

However, if we have plans for making the non-source generation Json serializer APIs work with trimming in 6.0, it might not be worth the effort of removing these attributes now, just to add them back in the near future.

cc @vitek-karas @agocke @layomia @steveharter

Author: eerhardt
Assignees: -
Labels:

area-System.Text.Json, untriaged

Milestone: -

@vitek-karas
Copy link
Member

I think we should remove them - as mentioned they are not enough and won't help in most cases anyway.

However, if we have plans for making the non-source generation Json serializer APIs work with trimming in 6.0, it might not be worth the effort of removing these attributes now, just to add them back in the near future.

If we do come up with a solution, I doubt it will be using the exact same annotations, so we would have to change this anyway. I don't mind revisiting this code again, if we have a reason to do so.

@eerhardt
Copy link
Member Author

eerhardt commented May 5, 2021

Just an FYI - we have trimming tests for these attributes:

using (var stream = new MemoryStream())
{
MyStruct obj = default;
await JsonSerializer.SerializeAsync(stream, obj, typeof(MyStruct));
string actual = Encoding.UTF8.GetString(stream.ToArray());
if (!TestHelper.JsonEqual(@"{""X"":0,""Y"":0}", actual))
{
return -1;
}

I assume as part of this work, we would be deleting those tests as well.

@eerhardt
Copy link
Member Author

@steveharter @layomia - I plan on working on this. Just ensuring you don't have any objections to removing these attributes.

eerhardt added a commit to eerhardt/runtime that referenced this issue May 25, 2021
@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label May 25, 2021
eerhardt added a commit that referenced this issue May 29, 2021
* Remove DynamicallyAccessedMembers on JsonSerializer

Fix #52268

* Remove DynamicallyAccessedMembers from System.Net.Http.Json

These are no longer required since System.Text.Json doesn't have these annotations anymore.

* Update PreviousNetCoreApp baseline for attribute removal

* Fix trimming tests on browser-wasm

* Fix Json tests on EnableAggressiveTrimming leg
@ghost ghost removed the in-pr There is an active PR which will close this issue when it is merged label May 29, 2021
@davidfowl
Copy link
Member

Didn't we decide that if we had a special [DAM] we could propagate these from user code to preserve type the call sites?

@eerhardt
Copy link
Member Author

Yes, when the linker supports making a custom [DAM], then we can mark these methods with that. But we don’t have that feature yet.

@ghost ghost locked as resolved and limited conversation to collaborators Jun 28, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Text.Json untriaged New issue has not been triaged by the area owner
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants