Skip to content

Commit 6aae812

Browse files
committed
json: use source generation for JSON serialization
1 parent 6074c61 commit 6aae812

File tree

9 files changed

+92
-46
lines changed

9 files changed

+92
-46
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using System.Text.Json.Serialization;
2+
3+
namespace Atlassian.Bitbucket;
4+
5+
[JsonSourceGenerationOptions(
6+
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
7+
PropertyNameCaseInsensitive = true
8+
)]
9+
[JsonSerializable(typeof(BitbucketTokenEndpointResponseJson))]
10+
[JsonSerializable(typeof(Cloud.UserInfo), TypeInfoPropertyName = "Cloud_UserInfo")]
11+
[JsonSerializable(typeof(DataCenter.UserInfo), TypeInfoPropertyName = "DataCenter_UserInfo")]
12+
[JsonSerializable(typeof(DataCenter.LoginOptions))]
13+
internal partial class BitbucketJsonSerializerContext : JsonSerializerContext
14+
{
15+
}

src/shared/Atlassian.Bitbucket/BitbucketOAuth2Client.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Net.Http;
4+
using System.Text.Json.Serialization;
45
using System.Threading;
56
using System.Threading.Tasks;
67
using GitCredentialManager;
@@ -42,7 +43,7 @@ protected override bool TryCreateTokenEndpointResult(string json, out OAuth2Toke
4243
// We override the token endpoint response parsing because the Bitbucket authority returns
4344
// the non-standard 'scopes' property for the list of scopes, rather than the (optional)
4445
// 'scope' (note the singular vs plural) property as outlined in the standard.
45-
if (TryDeserializeJson(json, out BitbucketTokenEndpointResponseJson jsonObj))
46+
if (TryDeserializeJson(json, BitbucketJsonSerializerContext.Default, out BitbucketTokenEndpointResponseJson jsonObj))
4647
{
4748
result = jsonObj.ToResult();
4849
return true;

src/shared/Atlassian.Bitbucket/Cloud/BitbucketRestApi.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,7 @@ public async Task<RestApiResult<IUserInfo>> GetUserInformationAsync(string userN
4343

4444
if (response.IsSuccessStatusCode)
4545
{
46-
var obj = JsonSerializer.Deserialize<UserInfo>(json,
47-
new JsonSerializerOptions
48-
{
49-
PropertyNameCaseInsensitive = true,
50-
});
46+
UserInfo obj = JsonSerializer.Deserialize(json, BitbucketJsonSerializerContext.Default.Cloud_UserInfo);
5147

5248
return new RestApiResult<IUserInfo>(response.StatusCode, obj);
5349
}

src/shared/Atlassian.Bitbucket/DataCenter/BitbucketRestApi.cs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,7 @@ public async Task<List<AuthenticationMethod>> GetAuthenticationMethodsAsync()
107107

108108
if (response.IsSuccessStatusCode)
109109
{
110-
var loginOptions = JsonSerializer.Deserialize<LoginOptions>(json,
111-
new JsonSerializerOptions
112-
{
113-
PropertyNameCaseInsensitive = true,
114-
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
115-
});
110+
LoginOptions loginOptions = JsonSerializer.Deserialize(json, BitbucketJsonSerializerContext.Default.LoginOptions);
116111

117112
if (loginOptions.Results.Any(r => "LOGIN_FORM".Equals(r.Type)))
118113
{
@@ -151,4 +146,4 @@ private Uri ApiUri
151146
}
152147
}
153148
}
154-
}
149+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using System.Text.Json.Serialization;
2+
3+
namespace GitCredentialManager.Authentication.OAuth.Json;
4+
5+
[JsonSourceGenerationOptions(
6+
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
7+
PropertyNameCaseInsensitive = true
8+
)]
9+
[JsonSerializable(typeof(DeviceAuthorizationEndpointResponseJson))]
10+
[JsonSerializable(typeof(ErrorResponseJson))]
11+
[JsonSerializable(typeof(TokenEndpointResponseJson))]
12+
public partial class OAuthJsonSerializerContext : JsonSerializerContext
13+
{
14+
}

src/shared/Core/Authentication/OAuth/OAuth2Client.cs

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Threading.Tasks;
77
using GitCredentialManager.Authentication.OAuth.Json;
88
using System.Text.Json;
9+
using System.Text.Json.Serialization;
910

1011
namespace GitCredentialManager.Authentication.OAuth
1112
{
@@ -213,7 +214,8 @@ public async Task<OAuth2DeviceCodeResult> GetDeviceCodeAsync(IEnumerable<string>
213214
{
214215
string json = await response.Content.ReadAsStringAsync();
215216

216-
if (response.IsSuccessStatusCode && TryDeserializeJson(json, out DeviceAuthorizationEndpointResponseJson jsonObj))
217+
if (response.IsSuccessStatusCode && TryDeserializeJson(json, OAuthJsonSerializerContext.Default,
218+
out DeviceAuthorizationEndpointResponseJson jsonObj))
217219
{
218220
return jsonObj.ToResult();
219221
}
@@ -321,12 +323,9 @@ public async Task<OAuth2TokenResult> GetTokenByDeviceCodeAsync(OAuth2DeviceCodeR
321323
return result;
322324
}
323325

324-
var error = JsonSerializer.Deserialize<ErrorResponseJson>(json, new JsonSerializerOptions
325-
{
326-
PropertyNameCaseInsensitive = true
327-
});
326+
TryDeserializeJson(json, OAuthJsonSerializerContext.Default, out ErrorResponseJson error);
328327

329-
switch (error.Error)
328+
switch (error?.Error)
330329
{
331330
case OAuth2Constants.DeviceAuthorization.Errors.AuthorizationPending:
332331
// Retry with the current polling interval value
@@ -358,7 +357,7 @@ public async Task<OAuth2TokenResult> GetTokenByDeviceCodeAsync(OAuth2DeviceCodeR
358357

359358
protected virtual bool TryCreateTokenEndpointResult(string json, out OAuth2TokenResult result)
360359
{
361-
if (TryDeserializeJson(json, out TokenEndpointResponseJson jsonObj))
360+
if (TryDeserializeJson(json, OAuthJsonSerializerContext.Default, out TokenEndpointResponseJson jsonObj))
362361
{
363362
result = jsonObj.ToResult();
364363
return true;
@@ -368,9 +367,9 @@ protected virtual bool TryCreateTokenEndpointResult(string json, out OAuth2Token
368367
return false;
369368
}
370369

371-
protected virtual bool TryCreateExceptionFromResponse(string json, out OAuth2Exception exception)
370+
private static bool TryCreateExceptionFromResponse(string json, out OAuth2Exception exception)
372371
{
373-
if (TryDeserializeJson(json, out ErrorResponseJson obj))
372+
if (TryDeserializeJson(json, OAuthJsonSerializerContext.Default, out ErrorResponseJson obj))
374373
{
375374
exception = obj.ToException();
376375
return true;
@@ -397,7 +396,7 @@ private HttpRequestMessage CreateRequestMessage(HttpMethod method, Uri requestUr
397396
return request;
398397
}
399398

400-
protected Exception CreateExceptionFromResponse(string json)
399+
private Exception CreateExceptionFromResponse(string json)
401400
{
402401
if (TryCreateExceptionFromResponse(json, out OAuth2Exception exception))
403402
{
@@ -410,11 +409,11 @@ protected Exception CreateExceptionFromResponse(string json)
410409
return new Trace2OAuth2Exception(_trace2, message, format);
411410
}
412411

413-
protected static bool TryDeserializeJson<T>(string json, out T obj)
412+
protected static bool TryDeserializeJson<T>(string json, JsonSerializerContext context, out T obj)
414413
{
415414
try
416415
{
417-
obj = JsonSerializer.Deserialize<T>(json);
416+
obj = (T)JsonSerializer.Deserialize(json, typeof(T), context);
418417
return true;
419418
}
420419
catch

src/shared/Core/Trace2Message.cs

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,36 @@
66

77
namespace GitCredentialManager;
88

9+
public class JsonSnakeCaseEnumConverter : JsonStringEnumConverter
10+
{
11+
public JsonSnakeCaseEnumConverter()
12+
: base(JsonNamingPolicy.SnakeCaseLower, false) { }
13+
}
14+
15+
[JsonSourceGenerationOptions(
16+
PropertyNamingPolicy = JsonKnownNamingPolicy.SnakeCaseLower,
17+
PropertyNameCaseInsensitive = true,
18+
Converters = new[] { typeof(JsonSnakeCaseEnumConverter) }
19+
)]
20+
[JsonSerializable(typeof(VersionMessage))]
21+
[JsonSerializable(typeof(StartMessage))]
22+
[JsonSerializable(typeof(ExitMessage))]
23+
[JsonSerializable(typeof(ExitMessage))]
24+
[JsonSerializable(typeof(ChildStartMessage))]
25+
[JsonSerializable(typeof(ChildExitMessage))]
26+
[JsonSerializable(typeof(ErrorMessage))]
27+
[JsonSerializable(typeof(RegionEnterMessage))]
28+
[JsonSerializable(typeof(RegionLeaveMessage))]
29+
internal partial class Trace2JsonSerializerContext : JsonSerializerContext
30+
{
31+
}
32+
933
public abstract class Trace2Message
1034
{
1135
private const int SourceColumnMaxWidth = 23;
1236
private const string NormalPerfTimeFormat = "HH:mm:ss.ffffff";
1337

1438
protected const string EmptyPerformanceSpan = "| | | | ";
15-
protected static readonly JsonSerializerOptions JsonSerializerOptions = new()
16-
{
17-
PropertyNameCaseInsensitive = true,
18-
Converters = { new JsonStringEnumConverter(new SnakeCaseNamingPolicy()) }
19-
};
2039

2140
[JsonPropertyName("event")]
2241
[JsonPropertyOrder(1)]
@@ -194,7 +213,7 @@ public class VersionMessage : Trace2Message
194213

195214
public override string ToJson()
196215
{
197-
return JsonSerializer.Serialize(this, JsonSerializerOptions);
216+
return JsonSerializer.Serialize(this, Trace2JsonSerializerContext.Default.VersionMessage);
198217
}
199218

200219
public override string ToNormalString()
@@ -230,7 +249,7 @@ public class StartMessage : Trace2Message
230249

231250
public override string ToJson()
232251
{
233-
return JsonSerializer.Serialize(this, JsonSerializerOptions);
252+
return JsonSerializer.Serialize(this, Trace2JsonSerializerContext.Default.StartMessage);
234253
}
235254

236255
public override string ToNormalString()
@@ -266,7 +285,7 @@ public class ExitMessage : Trace2Message
266285

267286
public override string ToJson()
268287
{
269-
return JsonSerializer.Serialize(this, JsonSerializerOptions);
288+
return JsonSerializer.Serialize(this, Trace2JsonSerializerContext.Default.ExitMessage);
270289
}
271290

272291
public override string ToNormalString()
@@ -314,7 +333,7 @@ public class ChildStartMessage : Trace2Message
314333

315334
public override string ToJson()
316335
{
317-
return JsonSerializer.Serialize(this, JsonSerializerOptions);
336+
return JsonSerializer.Serialize(this, Trace2JsonSerializerContext.Default.ChildStartMessage);
318337
}
319338

320339
public override string ToNormalString()
@@ -371,7 +390,7 @@ public class ChildExitMessage : Trace2Message
371390

372391
public override string ToJson()
373392
{
374-
return JsonSerializer.Serialize(this, JsonSerializerOptions);
393+
return JsonSerializer.Serialize(this, Trace2JsonSerializerContext.Default.ChildExitMessage);
375394
}
376395

377396
public override string ToNormalString()
@@ -415,7 +434,7 @@ public class ErrorMessage : Trace2Message
415434

416435
public override string ToJson()
417436
{
418-
return JsonSerializer.Serialize(this, JsonSerializerOptions);
437+
return JsonSerializer.Serialize(this, Trace2JsonSerializerContext.Default.ErrorMessage);
419438
}
420439

421440
public override string ToNormalString()
@@ -473,7 +492,7 @@ public class RegionEnterMessage : RegionMessage
473492
{
474493
public override string ToJson()
475494
{
476-
return JsonSerializer.Serialize(this, JsonSerializerOptions);
495+
return JsonSerializer.Serialize(this, Trace2JsonSerializerContext.Default.RegionEnterMessage);
477496
}
478497

479498
public override string ToNormalString()
@@ -504,7 +523,7 @@ public class RegionLeaveMessage : RegionMessage
504523

505524
public override string ToJson()
506525
{
507-
return JsonSerializer.Serialize(this, JsonSerializerOptions);
526+
return JsonSerializer.Serialize(this, Trace2JsonSerializerContext.Default.RegionLeaveMessage);
508527
}
509528

510529
public override string ToNormalString()
@@ -527,9 +546,3 @@ protected override string GetEventMessage(Trace2FormatTarget formatTarget)
527546
return Message;
528547
}
529548
}
530-
531-
public class SnakeCaseNamingPolicy : JsonNamingPolicy
532-
{
533-
public override string ConvertName(string name) =>
534-
name.ToSnakeCase();
535-
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
namespace GitHub;
2+
3+
using System.Text.Json.Serialization;
4+
5+
[JsonSourceGenerationOptions(
6+
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
7+
PropertyNameCaseInsensitive = true
8+
)]
9+
[JsonSerializable(typeof(GitHubUserInfo))]
10+
[JsonSerializable(typeof(GitHubMetaInfo))]
11+
internal partial class GitHubJsonSerializerContext : JsonSerializerContext
12+
{
13+
}

src/shared/GitHub/GitHubRestApi.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ public async Task<GitHubUserInfo> GetUserInfoAsync(Uri targetUri, string accessT
106106

107107
string json = await response.Content.ReadAsStringAsync();
108108

109-
return JsonSerializer.Deserialize<GitHubUserInfo>(json);
109+
return JsonSerializer.Deserialize(json, GitHubJsonSerializerContext.Default.GitHubUserInfo);
110110
}
111111
}
112112
}
@@ -125,7 +125,7 @@ public async Task<GitHubMetaInfo> GetMetaInfoAsync(Uri targetUri)
125125

126126
string json = await response.Content.ReadAsStringAsync();
127127

128-
return JsonSerializer.Deserialize<GitHubMetaInfo>(json);
128+
return JsonSerializer.Deserialize(json, GitHubJsonSerializerContext.Default.GitHubMetaInfo);
129129
}
130130
}
131131

0 commit comments

Comments
 (0)