-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Improve feature parity between JsonSerializerOptions and JsonSourceGenerationOptionsAttribute #57321
Comments
Tagging subscribers to this area: @eiriktsarpalis, @layomia Issue DetailsCurrently source generator for JSON serialization in It would be really helpful if these missing options could be added to the
|
Have you tried using the generated ctor on your context type that takes a e.g. [JsonSerializable(typeof(Foo))]
internal partial sealed class MyContext : JsonSerializerContext { }
JsonSerializerOptions options = new() { ... };
MyContext context = new(options);
JsonSerializer.Serialize(foo, context.Foo); |
Yes, that can be used as a workaround, but the generator still forces public API of my custom Ideally even the constructors would not be automatically generated and left to the developer. |
@layomia given that there's a workaround, does this meet the bar for 6.0.0? |
Moving to 7.0.0, we need to think about API design for this particular use case and we have a 6.0 workaround via the generated constructors. |
Hey folks, Would love to see this added so we can avoid {
"property": "x"
} into public sealed record Poco
{
public string Property { get; set; }
} Without needing to do any additional work. Currently we have to: public sealed record Poco
{
[JsonPropertyName("property")]
public string Property { get; set; }
} |
Have you tried using the string json = JsonSerializer.Serialize(new Poco { Property = "prop" }, MyContext.Default.Poco);
Console.WriteLine(json); // {"property":"prop"}
[JsonSourceGenerationOptions(PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase)]
[JsonSerializable(typeof(Poco))]
internal partial class MyContext : JsonSerializerContext { }
public sealed record Poco
{
public string Property { get; set; }
} |
Deleted my previous comment, I got it working with |
Background and MotivationWe should close the gap between Currently specifying options beyond what is offered by // can't use ContextWithAllOptionsSet.Default, need to use a custom instance intead
var options = new JsonSourceGenerationOptions(JsonSerializerDefaults.Web) { WriteIndented = true };
var customContext = new ContextWithAllOptionsSet(options);
[JsonSerializable(typeof(PersonStruct))]
public partial class ContextWithAllOptionsSet : JsonSerializerContext
{ } API ProposalThe proposed new properties/constructors are taken directly from the namespace System.Text.Json.Serialization;
public partial class JsonSourceGenerationOptionsAttribute
{
public JsonSourceGenerationOptionsAttribute();
+ public JsonSourceGenerationOptionsAttribute(JsonSerializerDefaults defaults);
+ public bool AllowTrailingCommas { get; set; }
+ public Type[]? Converters { get; set; }
+ public int DefaultBufferSize { get; set; }
public JsonIgnoreCondition DefaultIgnoreCondition { get; set; }
+ public JsonKnownNamingPolicy DictionaryKeyPolicy { get; set; }
public bool IgnoreReadOnlyFields { get; set; }
public bool IgnoreReadOnlyProperties { get; set; }
public bool IncludeFields { get; set; }
+ public int MaxDepth { get; set; }
+ public JsonNumberHandling NumberHandling { get; set; }
+ public JsonObjectCreationHandling PreferredObjectCreationHandling { get; set; }
+ public bool PropertyNameCaseInsensitive { get; set; }
public JsonKnownNamingPolicy PropertyNamingPolicy { get; set; }
+ public JsonCommentHandling ReadCommentHandling { get; set; }
+ public JsonUnknownTypeHandling UnknownTypeHandling { get; set; }
+ public JsonUnmappedMemberHandling UnmappedMemberHandling { get; set; }
public bool WriteIndented { get; set; }
} Note that the above leaves out the API UsageThe following declaration [JsonSourceGenerationOptions(JsonSerializerDefaults.Web,
AllowTrailingCommas = true,
Converters = new[] { typeof(JsonStringEnumConverter<BindingFlags>), typeof(JsonStringEnumConverter<JsonIgnoreCondition>) },
DefaultBufferSize = 128,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault,
DictionaryKeyPolicy = JsonKnownNamingPolicy.SnakeCaseUpper,
IgnoreReadOnlyFields = true,
IgnoreReadOnlyProperties = true,
IncludeFields = true,
MaxDepth = 1024,
NumberHandling = JsonNumberHandling.WriteAsString,
PreferredObjectCreationHandling = JsonObjectCreationHandling.Replace,
PropertyNameCaseInsensitive = true,
PropertyNamingPolicy = JsonKnownNamingPolicy.KebabCaseUpper,
ReadCommentHandling = JsonCommentHandling.Skip,
UnknownTypeHandling = JsonUnknownTypeHandling.JsonNode,
UnmappedMemberHandling = JsonUnmappedMemberHandling.Disallow,
WriteIndented = true)]
[JsonSerializable(typeof(PersonStruct))]
public partial class ContextWithAllOptionsSet : JsonSerializerContext
{ } Will result in the following default options instance being generated private readonly static global::System.Text.Json.JsonSerializerOptions s_defaultOptions = new(global::System.Text.Json.JsonSerializerDefaults.Web)
{
AllowTrailingCommas = true,
Converters =
{
new global::System.Text.Json.Serialization.JsonStringEnumConverter<global::System.Reflection.BindingFlags>(),
new global::System.Text.Json.Serialization.JsonStringEnumConverter<global::System.Text.Json.Serialization.JsonIgnoreCondition>(),
},
DefaultBufferSize = 128,
DefaultIgnoreCondition = global::System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingDefault,
DictionaryKeyPolicy = global::System.Text.Json.JsonNamingPolicy.SnakeCaseUpper,
IgnoreReadOnlyFields = true,
IgnoreReadOnlyProperties = true,
IncludeFields = true,
MaxDepth = 1024,
NumberHandling = global::System.Text.Json.Serialization.JsonNumberHandling.WriteAsString,
PreferredObjectCreationHandling = global::System.Text.Json.Serialization.JsonObjectCreationHandling.Replace,
PropertyNameCaseInsensitive = true,
PropertyNamingPolicy = global::System.Text.Json.JsonNamingPolicy.KebabCaseUpper,
ReadCommentHandling = global::System.Text.Json.JsonCommentHandling.Skip,
UnknownTypeHandling = global::System.Text.Json.Serialization.JsonUnknownTypeHandling.JsonNode,
UnmappedMemberHandling = global::System.Text.Json.Serialization.JsonUnmappedMemberHandling.Disallow,
WriteIndented = true,
}; |
namespace System.Text.Json.Serialization;
public partial class JsonSourceGenerationOptionsAttribute
{
public JsonSourceGenerationOptionsAttribute();
+ public JsonSourceGenerationOptionsAttribute(JsonSerializerDefaults defaults);
+ public bool AllowTrailingCommas { get; set; }
+ public Type[]? Converters { get; set; }
+ public int DefaultBufferSize { get; set; }
public JsonIgnoreCondition DefaultIgnoreCondition { get; set; }
+ public JsonKnownNamingPolicy DictionaryKeyPolicy { get; set; }
public bool IgnoreReadOnlyFields { get; set; }
public bool IgnoreReadOnlyProperties { get; set; }
public bool IncludeFields { get; set; }
+ public int MaxDepth { get; set; }
+ public JsonNumberHandling NumberHandling { get; set; }
+ public JsonObjectCreationHandling PreferredObjectCreationHandling { get; set; }
+ public bool PropertyNameCaseInsensitive { get; set; }
public JsonKnownNamingPolicy PropertyNamingPolicy { get; set; }
+ public JsonCommentHandling ReadCommentHandling { get; set; }
+ public JsonUnknownTypeHandling UnknownTypeHandling { get; set; }
+ public JsonUnmappedMemberHandling UnmappedMemberHandling { get; set; }
public bool WriteIndented { get; set; }
} |
EDIT See #57321 (comment) for an API proposal.
Original Proposal
Currently source generator for JSON serialization in `System.Text.Json` creates a static property named `Default` that receives default `JsonSerializerOptions` defined by the source generator. These can be modified by using `JsonSourceGenerationOptionsAttribute`, but several options are missing and cannot be set, e.g. `PropertyNameCaseInsensitive`, `NumberHandling`, `DictionaryKeyPolicy`...
It would be really helpful if these missing options could be added to the
JsonSourceGenerationOptionsAttribute
or at least disable generating of theDefault
property, so we could provide our own configuration for the default instance.The text was updated successfully, but these errors were encountered: