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

[System.Text.Json] Why does converters seem to not provide the name to serialize to? #36761

Closed
AraHaan opened this issue May 20, 2020 · 6 comments

Comments

@AraHaan
Copy link
Member

AraHaan commented May 20, 2020

So I got some code to a converter. After looking further I noticed I used the wrong value writers in the Write method due to the fact that the ones that needs the name to serialize to is missing the actual name. Also realized the ones that are used in this code is for json arrays.

public class DatumAttributes
{
    [JsonPropertyName("currently_entitled_amount_cents")]
    public long CurrentlyEntitledAmountCents { get; set; }

    [JsonPropertyName("full_name")]
    public string? FullName { get; set; }

    [JsonPropertyName("is_follower")]
    public bool IsFollower { get; set; }

    [JsonPropertyName("last_charge_date")]
    public DateTimeOffset? LastChargeDate { get; set; }

    [JsonPropertyName("last_charge_status")]
    public string? LastChargeStatus { get; set; }

    [JsonPropertyName("lifetime_support_cents")]
    public long LifetimeSupportCents { get; set; }

    [JsonPropertyName("patron_status")]
    [JsonConverter(typeof(PatronStatusConverter))]
    public PatronStatus PatronStatus { get; set; }
}

public enum PatronStatus { Null, ActivePatron, DeclinedPatron, FormerPatron };

internal class PatronStatusConverter : JsonConverter<PatronStatus>
{
    /// <inheritdoc />
    public override bool CanConvert(Type t)
        => t == typeof(PatronStatus) || t == typeof(PatronStatus?);

    /// <inheritdoc />
    public override PatronStatus Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        var value = reader.GetString();
        return string.IsNullOrEmpty(value)
            ? PatronStatus.Null
            : (value switch
        {
            "active_patron" => PatronStatus.ActivePatron,
            "declined_patron" => PatronStatus.DeclinedPatron,
            "former_patron" => PatronStatus.FormerPatron,
            _ => throw new Exception("Cannot unmarshal type PatronStatus"),
        });
    }

    /// <inheritdoc />
    public override void Write(Utf8JsonWriter writer, PatronStatus value, JsonSerializerOptions options)
    {
        switch (value)
        {
            case PatronStatus.ActivePatron:
                writer.WriteStringValue("active_patron");
                return;
            case PatronStatus.DeclinedPatron:
                writer.WriteStringValue("declined_patron");
                return;
            case PatronStatus.FormerPatron:
                writer.WriteStringValue("former_patron");
                return;
            case PatronStatus.Null:
                writer.WriteNullValue();
                return;
            default:
                throw new Exception("Cannot marshal type PatronStatus");
        }
    }
}

While the code at this state uses it once at the moment, What if I needed to use the converter and type on a few things. I would sure hate to hard code what the name to write the value to and then it being wrong. That is why I think somehow the Write method could possible get whatever name marked with the JsonPropertyName attribute and then use that string value from that attribute as means to properly write the value without hard coding anything into the converter.

@Dotnet-GitSync-Bot
Copy link
Collaborator

I couldn't figure out the best area label to add to this issue. Please help me learn by adding exactly one area label.

@Dotnet-GitSync-Bot Dotnet-GitSync-Bot added the untriaged New issue has not been triaged by the area owner label May 20, 2020
@AraHaan AraHaan changed the title Why does converters seem to not provide the name to serialize to? [System.Text.Json] Why does converters seem to not provide the name to serialize to? May 20, 2020
@AraHaan
Copy link
Member Author

AraHaan commented May 20, 2020

cc: @layomia @steveharter @jozkee

@jozkee jozkee added area-System.Text.Json untriaged New issue has not been triaged by the area owner and removed untriaged New issue has not been triaged by the area owner labels May 20, 2020
@layomia
Copy link
Contributor

layomia commented Jun 10, 2020

The scenario here may be addressed with work in #36785.

@layomia layomia removed the untriaged New issue has not been triaged by the area owner label Jun 10, 2020
@layomia layomia added this to the Future milestone Jun 10, 2020
@huoyaoyuan
Copy link
Member

@layomia Can the behavior of JsonStringEnumCoverter be modified to following JsonPropertyName?
This is technical breaking, but unlikely breaking real world things while upgrading.
However, it can break down level target when multi targeting.

@steveharter
Copy link
Member

somehow the Write method could possible get whatever name marked with the JsonPropertyName attribute and then use that string value from that attribute as means to properly write the value without hard coding anything into the converter.

If there are multiple JSON properties, then you are writing out a JSON object, not a simple value like in the sample above. In that case, yes the property names are typically hard-coded in the converter since the serializer does not expose them yet. However, it is possible to use reflection in the converter and check for the [JsonPropertyName] attribute for each property and use that instead of a hard-coded name; you'd also want to have caching of those names for performance.

As @layomia mentioned #36785 should address this scenario by providing a list of the serializable properties, which will have the JSON property name available from any [JsonPropertyName] attribute, as well as a way to get\set the actual property value.

@eiriktsarpalis
Copy link
Member

I believe this has been addressed by #63686.

@ghost ghost locked as resolved and limited conversation to collaborators Oct 2, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

7 participants