@@ -15,7 +15,8 @@ namespace Microsoft.Agents.Core.Serialization.Converters
15
15
public abstract class ConnectorConverter < T > : JsonConverter < T > where T : new ( )
16
16
{
17
17
private static readonly ConcurrentDictionary < Type , PropertyInfo [ ] > PropertyCache = new ( ) ;
18
- private static readonly ConcurrentDictionary < ( Type , bool , JsonNamingPolicy ) , Dictionary < string , PropertyInfo > > PropertyNameCache = new ( ) ;
18
+ private static readonly ConcurrentDictionary < ( Type , bool , Type ) , Dictionary < string , ( PropertyInfo , bool ) > > JsonPropertyMetadataCache = new ( ) ;
19
+
19
20
public override T Read ( ref Utf8JsonReader reader , Type typeToConvert , JsonSerializerOptions options )
20
21
{
21
22
if ( reader . TokenType != JsonTokenType . StartObject )
@@ -25,7 +26,7 @@ public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerial
25
26
26
27
var value = new T ( ) ;
27
28
28
- var properties = GetPropertyMap ( typeof ( T ) , options . PropertyNameCaseInsensitive , options . PropertyNamingPolicy ) ;
29
+ var propertyMetadataMap = GetJsonPropertyMetadata ( typeof ( T ) , options . PropertyNameCaseInsensitive , options . PropertyNamingPolicy ) ;
29
30
30
31
while ( reader . Read ( ) )
31
32
{
@@ -38,9 +39,9 @@ public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerial
38
39
{
39
40
var propertyName = reader . GetString ( ) ;
40
41
41
- if ( properties . ContainsKey ( propertyName ) )
42
+ if ( propertyMetadataMap . TryGetValue ( propertyName , out var entry ) )
42
43
{
43
- ReadProperty ( ref reader , value , propertyName , options , properties ) ;
44
+ ReadProperty ( ref reader , value , propertyName , options , entry . Property ) ;
44
45
}
45
46
else
46
47
{
@@ -58,11 +59,12 @@ public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions
58
59
59
60
var type = value . GetType ( ) ;
60
61
var properties = GetCachedProperties ( type ) ;
61
- var resolvedNames = GetPropertyMap ( type , false , options . PropertyNamingPolicy ) ; // case-insensitivity doesn’t matter here
62
+ var propertyMetadataMap = GetJsonPropertyMetadata ( type , false , options . PropertyNamingPolicy ) ; // case-insensitivity doesn’t matter here
63
+ var reverseMap = propertyMetadataMap . ToDictionary ( kv => kv . Value . Property , kv => ( kv . Key , kv . Value . IsIgnored ) ) ;
62
64
63
65
foreach ( var property in properties )
64
66
{
65
- if ( property . GetCustomAttribute < JsonIgnoreAttribute > ( ) != null )
67
+ if ( ! reverseMap . TryGetValue ( property , out var propertyMetadata ) || propertyMetadata . IsIgnored )
66
68
{
67
69
continue ;
68
70
}
@@ -83,7 +85,7 @@ public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions
83
85
if ( propertyValue != null || ! ( options . DefaultIgnoreCondition == JsonIgnoreCondition . WhenWritingNull ) )
84
86
85
87
{
86
- var propertyName = resolvedNames . FirstOrDefault ( kv => kv . Value == property ) . Key ?? property . Name ;
88
+ var propertyName = propertyMetadata . Key ?? property . Name ;
87
89
88
90
writer . WritePropertyName ( propertyName ) ;
89
91
@@ -258,10 +260,8 @@ protected void SetGenericProperty(ref Utf8JsonReader reader, Action<object> sett
258
260
setter ( deserialized ) ;
259
261
}
260
262
261
- private void ReadProperty ( ref Utf8JsonReader reader , T value , string propertyName , JsonSerializerOptions options , Dictionary < string , PropertyInfo > properties )
263
+ private void ReadProperty ( ref Utf8JsonReader reader , T value , string propertyName , JsonSerializerOptions options , PropertyInfo property )
262
264
{
263
- var property = properties [ propertyName ] ;
264
-
265
265
if ( TryReadExtensionData ( ref reader , value , property . Name , options ) )
266
266
{
267
267
return ;
@@ -302,31 +302,32 @@ private static PropertyInfo[] GetCachedProperties(Type type)
302
302
return PropertyCache . GetOrAdd ( type , static t => t . GetProperties ( ) ) ;
303
303
}
304
304
305
- private static Dictionary < string , PropertyInfo > GetPropertyMap ( Type type , bool caseInsensitive , JsonNamingPolicy ? namingPolicy )
305
+ private static Dictionary < string , ( PropertyInfo Property , bool IsIgnored ) > GetJsonPropertyMetadata ( Type type , bool caseInsensitive , JsonNamingPolicy ? namingPolicy )
306
306
{
307
- return PropertyNameCache . GetOrAdd ( ( type , caseInsensitive , namingPolicy ) , static key =>
307
+ var cacheKey = ( type , caseInsensitive , namingPolicy ? . GetType ( ) ) ;
308
+ return JsonPropertyMetadataCache . GetOrAdd ( cacheKey , key =>
308
309
{
309
- var ( t , insensitive , policy ) = key ;
310
+ var ( t , insensitive , _ ) = key ;
310
311
var comparer = insensitive ? StringComparer . OrdinalIgnoreCase : StringComparer . Ordinal ;
311
- var dict = new Dictionary < string , PropertyInfo > ( comparer ) ;
312
+ var metadata = new Dictionary < string , ( PropertyInfo , bool ) > ( comparer ) ;
312
313
313
314
foreach ( var prop in GetCachedProperties ( t ) )
314
315
{
315
316
var resolvedName = prop . GetCustomAttribute < JsonPropertyNameAttribute > ( ) ? . Name
316
- ?? policy ? . ConvertName ( prop . Name )
317
+ ?? namingPolicy ? . ConvertName ( prop . Name )
317
318
?? prop . Name ;
318
319
319
- if ( dict . ContainsKey ( resolvedName ) )
320
+ if ( metadata . ContainsKey ( resolvedName ) )
320
321
{
321
322
throw new InvalidOperationException (
322
323
$ "Duplicate JSON property name detected: '{ resolvedName } ' maps to multiple properties in type '{ t . FullName } '."
323
324
) ;
324
325
}
325
326
326
- dict [ resolvedName ] = prop ;
327
+ metadata [ resolvedName ] = ( prop , prop . GetCustomAttribute < JsonIgnoreAttribute > ( ) ? . Condition == JsonIgnoreCondition . Always ) ;
327
328
}
328
329
329
- return dict ;
330
+ return metadata ;
330
331
} ) ;
331
332
}
332
333
}
0 commit comments