-
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
Prevent source-gen from generating code for private fields and those marked with JsonIgnore #76919
Comments
Tagging subscribers to this area: @dotnet/area-system-text-json, @gregsdennis Issue DetailsOriginally posted: https://twitter.com/dotMorten/status/1580085523846074369 Following code: using System.Text.Json.Serialization;
[JsonSerializable(typeof(MyObject))]
[JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Metadata, IgnoreReadOnlyFields = true)]
internal partial class MyObjectSerializatioNContext : JsonSerializerContext
{
}
public class MyObject
{
[JsonPropertyName("test")]
public string? Test { get; set; }
[JsonIgnore]
private readonly ComplexObject? _data;
}
public class ComplexObject
{
private protected object _thisLock = new object();
} produces following build errors:
Here is the generated code - it produces way more than it should: // <auto-generated/>
#nullable enable annotations
#nullable disable warnings
// Suppress warnings about [Obsolete] member usage in generated code.
#pragma warning disable CS0618
internal partial class MyObjectSerializatioNContext
{
private global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::ComplexObject>? _ComplexObject;
/// <summary>
/// Defines the source generated JSON serialization contract metadata for a given type.
/// </summary>
public global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::ComplexObject> ComplexObject
{
get => _ComplexObject ??= Create_ComplexObject(Options);
}
// Intentionally not a static method because we create a delegate to it. Invoking delegates to instance
// methods is almost as fast as virtual calls. Static methods need to go through a shuffle thunk.
private global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::ComplexObject> Create_ComplexObject(global::System.Text.Json.JsonSerializerOptions options)
{
global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::ComplexObject>? jsonTypeInfo = null;
global::System.Text.Json.Serialization.JsonConverter? customConverter;
if (options.Converters.Count > 0 && (customConverter = GetRuntimeProvidedCustomConverter(options, typeof(global::ComplexObject))) != null)
{
jsonTypeInfo = global::System.Text.Json.Serialization.Metadata.JsonMetadataServices.CreateValueInfo<global::ComplexObject>(options, customConverter);
}
else
{
global::System.Text.Json.Serialization.Metadata.JsonObjectInfoValues<global::ComplexObject> objectInfo = new global::System.Text.Json.Serialization.Metadata.JsonObjectInfoValues<global::ComplexObject>()
{
ObjectCreator = static () => new global::ComplexObject(),
ObjectWithParameterizedConstructorCreator = null,
PropertyMetadataInitializer = _ => ComplexObjectPropInit(options),
ConstructorParameterMetadataInitializer = null,
NumberHandling = default,
SerializeHandler = null
};
jsonTypeInfo = global::System.Text.Json.Serialization.Metadata.JsonMetadataServices.CreateObjectInfo<global::ComplexObject>(options, objectInfo);
}
return jsonTypeInfo;
}
private static global::System.Text.Json.Serialization.Metadata.JsonPropertyInfo[] ComplexObjectPropInit(global::System.Text.Json.JsonSerializerOptions options)
{
global::System.Text.Json.Serialization.Metadata.JsonPropertyInfo[] properties = new global::System.Text.Json.Serialization.Metadata.JsonPropertyInfo[1];
global::System.Text.Json.Serialization.Metadata.JsonPropertyInfoValues<global::System.Object> info0 = new global::System.Text.Json.Serialization.Metadata.JsonPropertyInfoValues<global::System.Object>()
{
IsProperty = false,
IsPublic = false,
IsVirtual = false,
DeclaringType = typeof(global::ComplexObject),
Converter = null,
Getter = static (obj) => ((global::ComplexObject)obj)._thisLock!,
Setter = static (obj, value) => ((global::ComplexObject)obj)._thisLock = value!,
IgnoreCondition = null,
HasJsonInclude = false,
IsExtensionData = false,
NumberHandling = default,
PropertyName = "_thisLock",
JsonPropertyName = null
};
global::System.Text.Json.Serialization.Metadata.JsonPropertyInfo propertyInfo0 = global::System.Text.Json.Serialization.Metadata.JsonMetadataServices.CreatePropertyInfo<global::System.Object>(options, info0);
properties[0] = propertyInfo0;
return properties;
}
} cc: @dotMorten
|
This repro is surfacing a couple of issues:
I think we should keep this issue open to track the second issue. The first one should be tracked by #66679. |
LOL you beat me to it - didn't notice you logged it before I logged it this morning. Thanks :-) |
My issue is I'm trying to get our .NET 6 library compatible with trimming now that 7 is making it default, by moving to the new codegenerator. However this bug is blocking me from doing that, and I'd rather not wait until .net8 before we can officially support trimming in our SDK. What are the odds that this can be backported to the .net6 nuget package? |
Development for .NET 6 and .NET 7 has been concluded, and the bar for servicing these releases only includes high-impact issues like regressions, security issues or functional bugs without a known workaround. I'm not saying that this bug doesn't meet the bar, but generally speaking we need more evidence before we can get the gears rolling on a servicing fix. In your case, one simple workaround would be change your public class ComplexObject
{
private protected object ThisLock { get; } = new object();
} I acknowledge that your actual models might be more complicated than this example, but we can always work with you to extend that workaround to your actual codebase. |
Yes I simplified this example a lot. In the actual case there are 100s of classes that have metadata generated for it, bloating my assembly size. |
Unfortunatelly servicing bar is high at this point :-( System.Text.Json ships as a NuGet package though so once we have a fix you should be able to consume it first preview after that |
Would I be able to use the newer 7.0/8.0 nuget package to just generate the code and still be compatible with .net6? (and in a way where it isn't getting declared as a dependency in the generated nuspec?) |
You can use 7.0/8.0 System.Text.Json package on 6.0. You can see all supported target frameworks on nuget.org, i.e.: |
That's awesome. That would make the need for a backport less important. |
Just want to add here that this issue prevents me from moving from |
Related to #66679. |
I guess this workaround would not work in cases where one of the serialized class's properties or fields is of a type we can't modify, such as one of the types in System.Text.RegularExpressions—is there a recommended workaround for similar cases? public class SerializedClass
{
[JsonIgnore]
private Regex MyProperty { get; set; }
} Thank you. |
Moving to 8.0.0 since this seems to be impacting partner projects. cc @stephentoub |
Thank you @eiriktsarpalis. MUCH appreciated. |
Originally posted: https://twitter.com/dotMorten/status/1580085523846074369
Following code:
produces following build errors:
Here is the generated code - it produces way more than it should:
cc: @dotMorten
The text was updated successfully, but these errors were encountered: