File: Internal\Json\ValueConverter.cs
Web Access
Project: src\src\Grpc\JsonTranscoding\src\Microsoft.AspNetCore.Grpc.JsonTranscoding\Microsoft.AspNetCore.Grpc.JsonTranscoding.csproj (Microsoft.AspNetCore.Grpc.JsonTranscoding)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Text.Json;
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using Type = System.Type;
 
namespace Microsoft.AspNetCore.Grpc.JsonTranscoding.Internal.Json;
 
internal sealed class ValueConverter<TMessage> : SettingsConverterBase<TMessage> where TMessage : IMessage, new()
{
    public override bool HandleNull => true;
 
    public ValueConverter(JsonContext context) : base(context)
    {
    }
 
    public override TMessage? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        var message = new TMessage();
        var fields = message.Descriptor.Fields;
        switch (reader.TokenType)
        {
            case JsonTokenType.StartObject:
                {
                    var field = fields[Value.StructValueFieldNumber];
                    var structMessage = JsonSerializer.Deserialize(ref reader, field.MessageType.ClrType, options);
                    field.Accessor.SetValue(message, structMessage);
                    break;
                }
            case JsonTokenType.StartArray:
                {
                    var field = fields[Value.ListValueFieldNumber];
                    var list = JsonSerializer.Deserialize(ref reader, field.MessageType.ClrType, options);
                    field.Accessor.SetValue(message, list);
                    break;
                }
            case JsonTokenType.Comment:
                break;
            case JsonTokenType.String:
                fields[Value.StringValueFieldNumber].Accessor.SetValue(message, reader.GetString()!);
                break;
            case JsonTokenType.Number:
                fields[Value.NumberValueFieldNumber].Accessor.SetValue(message, reader.GetDouble());
                break;
            case JsonTokenType.True:
                fields[Value.BoolValueFieldNumber].Accessor.SetValue(message, true);
                break;
            case JsonTokenType.False:
                fields[Value.BoolValueFieldNumber].Accessor.SetValue(message, false);
                break;
            case JsonTokenType.Null:
                fields[Value.NullValueFieldNumber].Accessor.SetValue(message, 0);
                break;
            default:
                throw new InvalidOperationException("Unexpected token type: " + reader.TokenType);
        }
 
        return message;
    }
 
    public override void Write(Utf8JsonWriter writer, TMessage value, JsonSerializerOptions options)
    {
        var specifiedField = value.Descriptor.Oneofs[0].Accessor.GetCaseFieldDescriptor(value);
        if (specifiedField == null)
        {
            throw new InvalidOperationException("Value message must contain a value for the oneof.");
        }
 
        object v = specifiedField.Accessor.GetValue(value);
 
        switch (specifiedField.FieldNumber)
        {
            case Value.BoolValueFieldNumber:
            case Value.StringValueFieldNumber:
            case Value.NumberValueFieldNumber:
            case Value.StructValueFieldNumber:
            case Value.ListValueFieldNumber:
                JsonSerializer.Serialize(writer, v, v.GetType(), options);
                break;
            case Value.NullValueFieldNumber:
                writer.WriteNullValue();
                break;
            default:
                throw new InvalidOperationException("Unexpected case in struct field: " + specifiedField.FieldNumber);
        }
    }
}