-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
JsonSerializer support for fields & non-public accessors #34558
Comments
Why would it require runtime reflection and what speaks against it (Performance? Security?) and what speaks against it making it optional so in case of performance developers have a choice when performance / security isn't important? |
In a design where serializers/converters are generated at build-time to reduce the serializer's start-up cost and reduce/eliminate the usage of reflection features that are not supported by some platforms, non-public usage may not be supported dependent on the output assembly of the generated code. This may force the serializer down existing code paths which employ such reflection features as a fallback, which may be problematic depending on the scenario/platform.
This is a valid design possibility. These are very early thoughts on potential serializer code-gen work in the future; it is not clear yet how non-public usage may affect this work. |
namespace System.Text.Json
{
public partial class JsonSerializerOptions
{
public bool IncludeFields { get; set; }
}
}
namespace System.Text.Json.Serialization
{
[AttributeUsage(AttributeTargets.Property |
Attributes.Field, AllowMultiple = false)]
public sealed class JsonIncludeAttribute : JsonAttribute
{
public JsonIncludeAttribute();
}
} |
Updated proposal approved offline: namespace System.Text.Json
{
public partial class JsonSerializerOptions
{
public bool IgnoreReadOnlyFields { get; set; }
public bool IncludeFields { get; set; }
}
}
namespace System.Text.Json.Serialization
{
[AttributeUsage(AttributeTargets.Property |
Attributes.Field, AllowMultiple = false)]
public sealed class JsonIncludeAttribute : JsonAttribute
{
public JsonIncludeAttribute();
}
}
The serializer's defintion for "read only" is as follows:
This definition may be updated following the upcoming C# lang init-only properties (& perhaps fields), dependent on the type/reflection metadata made available. If init-only setters are available and public, it would be reasonable for the serializer to use them for deserialization. We would have to evaluate whether the serialization of such properties & fields should be influenced by cc @terrajobst |
Closing this composite issue as there are tracking issues for the sub-tasks:
|
For streamlined API review and due to common API suggestions, this issue addresses non-public accessor support, and field support.
Motivation
Using non-public accessors for serialization and deserialization
From #29743:
Non-public setters for public properties are not used when deserializing. Other serializers have this feature. As a workaround, user's have to write custom converter's for such POCOs, which isn't trivial in case of a complex object. This feature provides an opt-in for the serializer to use non-public setters.
Enabling non-public getter usage is included for parity with Newtonsoft.Json which supports this when the JsonProperty attribute is used, and to prevent complicating the API surface if this is ever desired in the future.
This feature was scoped out of v1 (3.x), as the objective was to support simple POCOs. We elected to make this feature opt-in due to security concerns with non-public support.
This feature does not include support for non-public properties.
A related feature that allows deserialization of immutable objects through parameterized constructors was recently added in #33444.
Field support
From #876:
There is no way to serialize and deserialize fields using
JsonSerializer
.While public fields are generally not recommended, they are used in .NET itself (see value tuples) and by users.
This feature was scoped out of v1 (3.x) due to lack of time, as we prioritized supporting simple POCOs with public properties.
We elected to have an opt-in model for field support because it would be a breaking change to support them by default, and also because public fields are generally not recommended. Other serializers, including
Newtonsoft.Json
,Utf8Json
, andJil
, support this feature by default.API proposal
Option 1
Usage
Including fields and using non-public accessors
Given a
Person
class:Alternatively,
An instance can be serialized or deserialized:
Including fields and ignoring non-public accessors
Given a
Person
class:Alternatively,
An instance can be serialized or deserialized:
Including fields globally but ignoring them for a particular type
Given an
Account
class:And a
Person
class:Account instances can be serialized and deserialized:
JsonObject
on an enumerable could be used to make the serializer treat it like an object with properties: Provide option for the serializer to treat IEnumerables like objects with members #1808.Option 2
Usage
Including fields and using non-public accessors
Given a
Person
class:Alternatively,
An instance can be serialized or deserialized:
Including fields and ignoring non-public accessors
Given a
Person
class:Alternatively,
An instance can be serialized or deserialized:
Including fields globally but ignoring them for a particular type
Given an
Account
class:And a
PersonClass
:Alternatively,
Account instances can be serialized and deserialized:
To override
JsonSerializer.IncludeFields
when set to true,[JsonIgnore]
would need to be set on each field to be ignored.Notes
The opt-in mechanism for non-public accessor is per property and per type, not "globally" on
JsonSerializerOptions
. This is to prevent non-public member access on types that are not owned by the user.Features involving the the use of non-public accessors, including constructors, getters, setters etc. may not be supported in the upcoming AOT/code-gen work due to the likely need to use runtime reflection for those scenarios.
The options on
JsonSerializerOptions
that apply to properties will also apply to fields. This is intuitive and keeps the API surface clean:IgnoreNullValues
PropertyNameCaseInsensitive
PropertyNamingPolicy
Existing attributes that apply to properties will also apply to fields:
JsonConverterAttribute
JsonExtensionDataAttribute
JsonIgnoreAttribute
JsonPropertyNameAttribute
Interfaces will not be added as a target until the implications for extended polymorphism support are understood. This is in keeping with JsonConverterAttribute where an interface is not a valid target: Add AttributeTargets.Interface to JsonConverterAttribute #33112.
As with public properties, public fields may also bind with constructor parameters during deserialization, with the same semantics.
The text was updated successfully, but these errors were encountered: