1+ using System ;
2+ using System . Collections . Generic ;
3+ using System . Reflection ;
4+ using System . Runtime . Serialization ;
5+ using System . Text . Json ;
6+ using System . Text . Json . Serialization ;
7+
8+ namespace Infobip . Api . Client
9+ {
10+
11+ /// <summary>
12+ /// System.Text.Json converter that serializes and deserializes enums using their <see cref="EnumMemberAttribute"/> values if present, else their names.
13+ /// Ensures proper enum (de)serialization for API models where JSON uses string values defined by <see cref="EnumMemberAttribute"/>.
14+ /// </summary>
15+ /// <typeparam name="T">Enum type to convert.</typeparam>
16+ public class JsonStringEnumMemberConverter < T > : JsonConverter < T > where T : struct , Enum
17+ {
18+ private readonly Dictionary < string , T > _fromValue ;
19+ private readonly Dictionary < T , string > _toValue ;
20+
21+ /// <summary>
22+ /// Initializes a new instance of <see cref="JsonStringEnumMemberConverter{T}"/>.
23+ /// Builds internal mappings of enum values to their <see cref="EnumMemberAttribute"/> strings.
24+ /// </summary>
25+ public JsonStringEnumMemberConverter ( )
26+ {
27+ _fromValue = new Dictionary < string , T > ( StringComparer . OrdinalIgnoreCase ) ;
28+ _toValue = new Dictionary < T , string > ( ) ;
29+ foreach ( var field in typeof ( T ) . GetFields ( BindingFlags . Public | BindingFlags . Static ) )
30+ {
31+ var enumValue = ( T ) field . GetValue ( null ) ;
32+ var enumMemberAttr = field . GetCustomAttribute < EnumMemberAttribute > ( ) ;
33+ var strValue = enumMemberAttr ? . Value ?? field . Name ;
34+ _fromValue [ strValue ] = enumValue ;
35+ _toValue [ enumValue ] = strValue ;
36+ }
37+ }
38+
39+ /// <summary>
40+ /// Reads and converts the JSON string value to the corresponding enum value,
41+ /// interpreting <see cref="EnumMemberAttribute.Value"/> if present.
42+ /// </summary>
43+ /// <param name="reader">The reader to read from.</param>
44+ /// <param name="typeToConvert">The type being converted.</param>
45+ /// <param name="options">Serialization options to use.</param>
46+ /// <returns>The converted enum value.</returns>
47+ /// <exception cref="JsonException">Thrown if JSON token is not a string or cannot be mapped to enum.</exception>
48+ public override T Read ( ref Utf8JsonReader reader , Type typeToConvert , JsonSerializerOptions options )
49+ {
50+ if ( reader . TokenType == JsonTokenType . String )
51+ {
52+ var enumString = reader . GetString ( ) ;
53+ if ( _fromValue . TryGetValue ( enumString , out var value ) )
54+ return value ;
55+ throw new JsonException ( $ "Unknown value '{ enumString } ' for enum '{ typeof ( T ) . Name } '") ;
56+ }
57+ throw new JsonException ( $ "Unexpected token parsing enum. Expected String, got { reader . TokenType } .") ;
58+ }
59+
60+ /// <summary>
61+ /// Writes the enum value as a JSON string, preferring the <see cref="EnumMemberAttribute.Value"/> if present.
62+ /// </summary>
63+ /// <param name="writer">The writer to write to.</param>
64+ /// <param name="value">The enum value to write.</param>
65+ /// <param name="options">Serialization options to use.</param>
66+ public override void Write ( Utf8JsonWriter writer , T value , JsonSerializerOptions options )
67+ {
68+ if ( _toValue . TryGetValue ( value , out var stringValue ) )
69+ writer . WriteStringValue ( stringValue ) ;
70+ else
71+ writer . WriteStringValue ( value . ToString ( ) ) ;
72+ }
73+ }
74+ }
0 commit comments