1+ using System . Reflection ;
2+ using System . Text . Json . Serialization ;
3+ using Google . Protobuf ;
4+ using Google . Protobuf . Reflection ;
5+
6+ namespace System . Text . Json . Protobuf ;
7+
8+ internal class ProtobufConverter < T > : JsonConverter < T ? > where T : class , IMessage , new ( )
9+ {
10+ private readonly List < FieldInfo > _fields = new ( ) ;
11+ private readonly Dictionary < string , FieldInfo > _fieldsLookup = new ( ) ;
12+
13+ public ProtobufConverter ( )
14+ {
15+ var propertyInfo = typeof ( T ) . GetProperty ( "Descriptor" , BindingFlags . Public | BindingFlags . Static ) ;
16+ var messageDescriptor = ( MessageDescriptor ) propertyInfo ? . GetValue ( null , null ) ! ;
17+
18+ foreach ( var fieldDescriptor in messageDescriptor . Fields . InDeclarationOrder ( ) )
19+ {
20+ var fieldInfo = new FieldInfo
21+ {
22+ Accessor = fieldDescriptor . Accessor ,
23+ IsRepeated = fieldDescriptor . IsRepeated ,
24+ FieldType = GetFieldType ( fieldDescriptor ) ,
25+ JsonName = fieldDescriptor . JsonName ,
26+ } ;
27+ _fieldsLookup . Add ( fieldDescriptor . JsonName , fieldInfo ) ;
28+ _fields . Add ( fieldInfo ) ;
29+ }
30+ }
31+
32+ public override T ? Read ( ref Utf8JsonReader reader , Type typeToConvert , JsonSerializerOptions options )
33+ {
34+ var obj = new T ( ) ;
35+
36+ if ( reader . TokenType != JsonTokenType . StartObject )
37+ {
38+ throw new JsonException ( $ "The JSON value could not be converted to { typeToConvert } .") ;
39+ }
40+
41+ // Process all properties.
42+ while ( true )
43+ {
44+ // Read the property name or EndObject.
45+ reader . Read ( ) ;
46+
47+ if ( reader . TokenType == JsonTokenType . EndObject )
48+ {
49+ break ;
50+ }
51+
52+ var propertyName = reader . GetString ( ) ;
53+
54+ if ( ! _fieldsLookup . TryGetValue ( propertyName , out var fieldInfo ) )
55+ {
56+ continue ;
57+ }
58+
59+ fieldInfo . Converter ??= InternalConverterFactory . Create ( fieldInfo . FieldType , fieldInfo . IsRepeated ) ;
60+
61+ reader . Read ( ) ;
62+ fieldInfo . Converter . Read ( ref reader , obj , fieldInfo . FieldType , options , fieldInfo . Accessor ) ;
63+ }
64+
65+ return obj ;
66+
67+ }
68+
69+ public override void Write ( Utf8JsonWriter writer , T ? value , JsonSerializerOptions options )
70+ {
71+ if ( value == null )
72+ {
73+ writer . WriteNullValue ( ) ;
74+ return ;
75+ }
76+
77+ writer . WriteStartObject ( ) ;
78+
79+ foreach ( var fieldInfo in _fields )
80+ {
81+ var obj = fieldInfo . Accessor . GetValue ( value ) ;
82+ if ( obj is { } propertyValue )
83+ {
84+ writer . WritePropertyName ( fieldInfo . JsonName ) ;
85+ fieldInfo . Converter ??= InternalConverterFactory . Create ( fieldInfo . FieldType , fieldInfo . IsRepeated ) ;
86+ fieldInfo . Converter . Write ( writer , propertyValue , options ) ;
87+ }
88+ }
89+
90+ writer . WriteEndObject ( ) ;
91+ }
92+
93+ private Type GetFieldType ( FieldDescriptor fieldDescriptor )
94+ {
95+ switch ( fieldDescriptor . FieldType )
96+ {
97+ case FieldType . Int32 :
98+ return typeof ( int ) ;
99+ case FieldType . Int64 :
100+ return typeof ( long ) ;
101+ default :
102+ throw new ArgumentOutOfRangeException ( ) ;
103+ }
104+ }
105+ }
0 commit comments