Json serializer code generator doesn't support internal constructors (original) (raw)

Description

If I have a public class that I want to be able to deserialize, but I don't want that class publicly constructable, I can no longer deserialize it, even though the generated deserializer code has access to the internal constructor.

This issue prevents moving from DataContractJsonSerializer to S.T.J.

Reproduction Steps

In a console app, add the following code:

using System.Text.Json; using System.Text.Json.Serialization;

string json = "{"name":"Hello World"}";

var obj = JsonSerializer.Deserialize(json, MyDataModelSerializationContext.Default.MyDataModel);

[JsonSerializable(typeof(MyDataModel))] [JsonSourceGenerationOptions(PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase)] internal partial class MyDataModelSerializationContext : JsonSerializerContext { }

public class MyDataModel { // [JsonConstructor] Won't make a difference internal MyDataModel() { } public string? Name { get; set; } }

Expected behavior

Object deserializes.

Actual behavior

Exception thrown on deserialize:

System.NotSupportedException: 'Deserialization of types without a parameterless constructor, a singular parameterized constructor, or a parameterized constructor annotated with 'JsonConstructorAttribute' is not supported. Type 'MyDataModel'. Path: $ | LineNumber: 0 | BytePositionInLine: 1.'
image

Looking at the generated code, you'll note the ObjectCreator is null.
image
Compare that to when the constructor is declared public:
image

A similar issue is hit with a data model like this:

internal class MyDataModel { [JsonPropertyName("name")] public string? Name { get; internal set; } }

In this case for this internal class, a setter isn't generated for the Name property and during serialization the value is never defined. Granted in this case there's no need to mark it internal since the entire class is already internal - however even if the class is public, I can't restrict the setter from public abuse and only allow the deserializer to set it.

Regression?

No response

Known Workarounds

Not really. If I make the entire class internal (and make the constructor public albeit it is effectively internal now), it works again. However I do want my class to be publicly accessible

Configuration

.net 6.0.401

Other information

No response