Skip to content

Commit 8d0f6af

Browse files
authored
[dotnet] [bidi] Use JsonSerializerContext to be AOT friendly (#15162)
1 parent 0bf5e9e commit 8d0f6af

File tree

5 files changed

+154
-13
lines changed

5 files changed

+154
-13
lines changed

dotnet/src/webdriver/BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ csharp_library(
5555
framework("nuget", "Microsoft.Bcl.AsyncInterfaces"),
5656
framework("nuget", "System.Threading.Tasks.Extensions"),
5757
framework("nuget", "System.Memory"),
58+
framework("nuget", "System.Runtime.CompilerServices.Unsafe"),
5859
framework("nuget", "System.Text.Encodings.Web"),
5960
framework("nuget", "System.Text.Json"),
6061
],
@@ -120,6 +121,7 @@ csharp_library(
120121
framework("nuget", "Microsoft.Bcl.AsyncInterfaces"),
121122
framework("nuget", "System.Threading.Tasks.Extensions"),
122123
framework("nuget", "System.Memory"),
124+
framework("nuget", "System.Runtime.CompilerServices.Unsafe"),
123125
framework("nuget", "System.Text.Encodings.Web"),
124126
framework("nuget", "System.Text.Json"),
125127
],

dotnet/src/webdriver/BiDi/Communication/Broker.cs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
// under the License.
1818
// </copyright>
1919

20+
using OpenQA.Selenium.BiDi.Communication.Json;
2021
using OpenQA.Selenium.BiDi.Communication.Json.Converters;
2122
using OpenQA.Selenium.BiDi.Communication.Transport;
2223
using OpenQA.Selenium.Internal.Logging;
@@ -53,14 +54,14 @@ public class Broker : IAsyncDisposable
5354
private Task? _eventEmitterTask;
5455
private CancellationTokenSource? _receiveMessagesCancellationTokenSource;
5556

56-
private readonly JsonSerializerOptions _jsonSerializerOptions;
57+
private readonly BiDiJsonSerializerContext _jsonSerializerContext;
5758

5859
internal Broker(BiDi bidi, ITransport transport)
5960
{
6061
_bidi = bidi;
6162
_transport = transport;
6263

63-
_jsonSerializerOptions = new JsonSerializerOptions
64+
var jsonSerializerOptions = new JsonSerializerOptions
6465
{
6566
PropertyNameCaseInsensitive = true,
6667
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
@@ -99,6 +100,8 @@ internal Broker(BiDi bidi, ITransport transport)
99100
new Json.Converters.Enumerable.GetRealmsResultConverter(),
100101
}
101102
};
103+
104+
_jsonSerializerContext = new BiDiJsonSerializerContext(jsonSerializerOptions);
102105
}
103106

104107
public async Task ConnectAsync(CancellationToken cancellationToken)
@@ -114,7 +117,7 @@ private async Task ReceiveMessagesAsync(CancellationToken cancellationToken)
114117
{
115118
while (!cancellationToken.IsCancellationRequested)
116119
{
117-
var message = await _transport.ReceiveAsJsonAsync<Message>(_jsonSerializerOptions, cancellationToken);
120+
var message = await _transport.ReceiveAsJsonAsync<Message>(_jsonSerializerContext, cancellationToken);
118121

119122
switch (message)
120123
{
@@ -145,7 +148,7 @@ private async Task ProcessEventsAwaiterAsync()
145148
{
146149
foreach (var handler in eventHandlers.ToArray()) // copy handlers avoiding modified collection while iterating
147150
{
148-
var args = (EventArgs)result.Params.Deserialize(handler.EventArgsType, _jsonSerializerOptions)!;
151+
var args = (EventArgs)result.Params.Deserialize(handler.EventArgsType, _jsonSerializerContext)!;
149152

150153
args.BiDi = _bidi;
151154

@@ -177,7 +180,7 @@ public async Task<TResult> ExecuteCommandAsync<TResult>(Command command, Command
177180
{
178181
var result = await ExecuteCommandCoreAsync(command, options).ConfigureAwait(false);
179182

180-
return (TResult)((JsonElement)result).Deserialize(typeof(TResult), _jsonSerializerOptions)!;
183+
return (TResult)((JsonElement)result).Deserialize(typeof(TResult), _jsonSerializerContext)!;
181184
}
182185

183186
public async Task ExecuteCommandAsync(Command command, CommandOptions? options)
@@ -199,7 +202,7 @@ private async Task<object> ExecuteCommandCoreAsync(Command command, CommandOptio
199202

200203
_pendingCommands[command.Id] = tcs;
201204

202-
await _transport.SendAsJsonAsync(command, _jsonSerializerOptions, cts.Token).ConfigureAwait(false);
205+
await _transport.SendAsJsonAsync(command, _jsonSerializerContext, cts.Token).ConfigureAwait(false);
203206

204207
return await tcs.Task.ConfigureAwait(false);
205208
}
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
// <copyright file="BiDiJsonSerializerContext.cs" company="Selenium Committers">
2+
// Licensed to the Software Freedom Conservancy (SFC) under one
3+
// or more contributor license agreements. See the NOTICE file
4+
// distributed with this work for additional information
5+
// regarding copyright ownership. The SFC licenses this file
6+
// to you under the Apache License, Version 2.0 (the
7+
// "License"); you may not use this file except in compliance
8+
// with the License. You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing,
13+
// software distributed under the License is distributed on an
14+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
// KIND, either express or implied. See the License for the
16+
// specific language governing permissions and limitations
17+
// under the License.
18+
// </copyright>
19+
20+
using System.Collections.Generic;
21+
using System.Text.Json.Serialization;
22+
23+
namespace OpenQA.Selenium.BiDi.Communication.Json;
24+
25+
#region https://github.com/dotnet/runtime/issues/72604
26+
[JsonSerializable(typeof(MessageSuccess))]
27+
[JsonSerializable(typeof(MessageError))]
28+
[JsonSerializable(typeof(MessageEvent))]
29+
30+
[JsonSerializable(typeof(Modules.Script.EvaluateResult.Success))]
31+
[JsonSerializable(typeof(Modules.Script.EvaluateResult.Exception))]
32+
33+
[JsonSerializable(typeof(Modules.Script.RemoteValue.Number), TypeInfoPropertyName = "Script_RemoteValue_Number")]
34+
[JsonSerializable(typeof(Modules.Script.RemoteValue.Boolean), TypeInfoPropertyName = "Script_RemoteValue_Boolean")]
35+
[JsonSerializable(typeof(Modules.Script.RemoteValue.String), TypeInfoPropertyName = "Script_RemoteValue_String")]
36+
[JsonSerializable(typeof(Modules.Script.RemoteValue.Null), TypeInfoPropertyName = "Script_RemoteValue_Null")]
37+
[JsonSerializable(typeof(Modules.Script.RemoteValue.Undefined), TypeInfoPropertyName = "Script_RemoteValue_Undefined")]
38+
[JsonSerializable(typeof(Modules.Script.RemoteValue.Symbol))]
39+
[JsonSerializable(typeof(Modules.Script.RemoteValue.Array), TypeInfoPropertyName = "Script_RemoteValue_Array")]
40+
[JsonSerializable(typeof(Modules.Script.RemoteValue.Object), TypeInfoPropertyName = "Script_RemoteValue_Object")]
41+
[JsonSerializable(typeof(Modules.Script.RemoteValue.Function))]
42+
[JsonSerializable(typeof(Modules.Script.RemoteValue.RegExp), TypeInfoPropertyName = "Script_RemoteValue_RegExp")]
43+
[JsonSerializable(typeof(Modules.Script.RemoteValue.RegExp.RegExpValue), TypeInfoPropertyName = "Script_RemoteValue_RegExp_RegExpValue")]
44+
[JsonSerializable(typeof(Modules.Script.RemoteValue.Date), TypeInfoPropertyName = "Script_RemoteValue_Date")]
45+
[JsonSerializable(typeof(Modules.Script.RemoteValue.Map), TypeInfoPropertyName = "Script_RemoteValue_Map")]
46+
[JsonSerializable(typeof(Modules.Script.RemoteValue.Set), TypeInfoPropertyName = "Script_RemoteValue_Set")]
47+
[JsonSerializable(typeof(Modules.Script.RemoteValue.WeakMap))]
48+
[JsonSerializable(typeof(Modules.Script.RemoteValue.WeakSet))]
49+
[JsonSerializable(typeof(Modules.Script.RemoteValue.Generator))]
50+
[JsonSerializable(typeof(Modules.Script.RemoteValue.Error))]
51+
[JsonSerializable(typeof(Modules.Script.RemoteValue.Proxy))]
52+
[JsonSerializable(typeof(Modules.Script.RemoteValue.Promise))]
53+
[JsonSerializable(typeof(Modules.Script.RemoteValue.TypedArray))]
54+
[JsonSerializable(typeof(Modules.Script.RemoteValue.ArrayBuffer))]
55+
[JsonSerializable(typeof(Modules.Script.RemoteValue.NodeList))]
56+
[JsonSerializable(typeof(Modules.Script.RemoteValue.HtmlCollection))]
57+
[JsonSerializable(typeof(Modules.Script.RemoteValue.Node))]
58+
[JsonSerializable(typeof(Modules.Script.RemoteValue.WindowProxy))]
59+
60+
[JsonSerializable(typeof(Modules.Script.RealmInfo.Window))]
61+
[JsonSerializable(typeof(Modules.Script.RealmInfo.DedicatedWorker))]
62+
[JsonSerializable(typeof(Modules.Script.RealmInfo.SharedWorker))]
63+
[JsonSerializable(typeof(Modules.Script.RealmInfo.ServiceWorker))]
64+
[JsonSerializable(typeof(Modules.Script.RealmInfo.Worker))]
65+
[JsonSerializable(typeof(Modules.Script.RealmInfo.PaintWorklet))]
66+
[JsonSerializable(typeof(Modules.Script.RealmInfo.AudioWorklet))]
67+
[JsonSerializable(typeof(Modules.Script.RealmInfo.Worklet))]
68+
69+
[JsonSerializable(typeof(Modules.Log.Entry.Console))]
70+
[JsonSerializable(typeof(Modules.Log.Entry.Javascript))]
71+
#endregion
72+
73+
[JsonSerializable(typeof(Command))]
74+
[JsonSerializable(typeof(Message))]
75+
76+
[JsonSerializable(typeof(Modules.Session.StatusResult))]
77+
[JsonSerializable(typeof(Modules.Session.NewResult))]
78+
79+
[JsonSerializable(typeof(Modules.Browser.CloseCommand), TypeInfoPropertyName = "Browser_CloseCommand")]
80+
[JsonSerializable(typeof(Modules.Browser.GetUserContextsResult))]
81+
[JsonSerializable(typeof(IReadOnlyList<Modules.Browser.UserContextInfo>))]
82+
83+
[JsonSerializable(typeof(Modules.BrowsingContext.CloseCommand), TypeInfoPropertyName = "BrowsingContext_CloseCommand")]
84+
[JsonSerializable(typeof(Modules.BrowsingContext.CreateResult))]
85+
[JsonSerializable(typeof(Modules.BrowsingContext.BrowsingContextInfo))]
86+
[JsonSerializable(typeof(Modules.BrowsingContext.NavigateResult))]
87+
[JsonSerializable(typeof(Modules.BrowsingContext.NavigationInfo))]
88+
[JsonSerializable(typeof(Modules.BrowsingContext.TraverseHistoryResult))]
89+
[JsonSerializable(typeof(Modules.BrowsingContext.LocateNodesResult))]
90+
[JsonSerializable(typeof(Modules.BrowsingContext.CaptureScreenshotResult))]
91+
[JsonSerializable(typeof(Modules.BrowsingContext.GetTreeResult))]
92+
[JsonSerializable(typeof(Modules.BrowsingContext.PrintResult))]
93+
[JsonSerializable(typeof(Modules.BrowsingContext.UserPromptOpenedEventArgs))]
94+
[JsonSerializable(typeof(Modules.BrowsingContext.UserPromptClosedEventArgs))]
95+
[JsonSerializable(typeof(Modules.BrowsingContext.Origin), TypeInfoPropertyName = "BrowsingContext_Origin")]
96+
97+
[JsonSerializable(typeof(Modules.Network.BytesValue.String), TypeInfoPropertyName = "Network_BytesValue_String")]
98+
[JsonSerializable(typeof(Modules.Network.UrlPattern.String), TypeInfoPropertyName = "Network_UrlPattern_String")]
99+
[JsonSerializable(typeof(Modules.Network.ContinueWithAuthParameters.Default), TypeInfoPropertyName = "Network_ContinueWithAuthParameters_Default")]
100+
[JsonSerializable(typeof(Modules.Network.AddInterceptResult))]
101+
[JsonSerializable(typeof(Modules.Network.BeforeRequestSentEventArgs))]
102+
[JsonSerializable(typeof(Modules.Network.ResponseStartedEventArgs))]
103+
[JsonSerializable(typeof(Modules.Network.ResponseCompletedEventArgs))]
104+
[JsonSerializable(typeof(Modules.Network.FetchErrorEventArgs))]
105+
[JsonSerializable(typeof(Modules.Network.AuthRequiredEventArgs))]
106+
107+
[JsonSerializable(typeof(Modules.Script.Channel), TypeInfoPropertyName = "Script_Channel")]
108+
[JsonSerializable(typeof(Modules.Script.LocalValue.String), TypeInfoPropertyName = "Script_LocalValue_String")]
109+
[JsonSerializable(typeof(Modules.Script.Target.Realm), TypeInfoPropertyName = "Script_Target_Realm")]
110+
[JsonSerializable(typeof(Modules.Script.Target.Context), TypeInfoPropertyName = "Script_Target_Context")]
111+
[JsonSerializable(typeof(Modules.Script.AddPreloadScriptResult))]
112+
[JsonSerializable(typeof(Modules.Script.EvaluateResult))]
113+
[JsonSerializable(typeof(Modules.Script.GetRealmsResult))]
114+
[JsonSerializable(typeof(Modules.Script.MessageEventArgs))]
115+
[JsonSerializable(typeof(Modules.Script.RealmDestroyedEventArgs))]
116+
[JsonSerializable(typeof(IReadOnlyList<Modules.Script.RealmInfo>))]
117+
118+
[JsonSerializable(typeof(Modules.Log.Entry))]
119+
120+
[JsonSerializable(typeof(Modules.Storage.GetCookiesResult))]
121+
[JsonSerializable(typeof(Modules.Storage.DeleteCookiesResult))]
122+
[JsonSerializable(typeof(Modules.Storage.SetCookieResult))]
123+
124+
[JsonSerializable(typeof(Modules.Input.PerformActionsCommand))]
125+
[JsonSerializable(typeof(Modules.Input.Pointer.Down), TypeInfoPropertyName = "Input_Pointer_Down")]
126+
[JsonSerializable(typeof(Modules.Input.Pointer.Up), TypeInfoPropertyName = "Input_Pointer_Up")]
127+
[JsonSerializable(typeof(Modules.Input.Pointer.Move), TypeInfoPropertyName = "Input_Pointer_Move")]
128+
[JsonSerializable(typeof(Modules.Input.Key.Down), TypeInfoPropertyName = "Input_Key_Down")]
129+
[JsonSerializable(typeof(Modules.Input.Key.Up), TypeInfoPropertyName = "Input_Key_Up")]
130+
[JsonSerializable(typeof(IEnumerable<Modules.Input.IPointerSourceAction>))]
131+
[JsonSerializable(typeof(IEnumerable<Modules.Input.IKeySourceAction>))]
132+
[JsonSerializable(typeof(IEnumerable<Modules.Input.INoneSourceAction>))]
133+
[JsonSerializable(typeof(IEnumerable<Modules.Input.IWheelSourceAction>))]
134+
135+
internal partial class BiDiJsonSerializerContext : JsonSerializerContext;

dotnet/src/webdriver/BiDi/Communication/Transport/ITransport.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@
1717
// under the License.
1818
// </copyright>
1919

20-
using System.Text.Json;
2120
using System.Threading.Tasks;
2221
using System.Threading;
2322
using System;
23+
using System.Text.Json.Serialization;
2424

2525
#nullable enable
2626

@@ -30,7 +30,7 @@ interface ITransport : IDisposable
3030
{
3131
Task ConnectAsync(CancellationToken cancellationToken);
3232

33-
Task<T> ReceiveAsJsonAsync<T>(JsonSerializerOptions jsonSerializerOptions, CancellationToken cancellationToken);
33+
Task<T> ReceiveAsJsonAsync<T>(JsonSerializerContext jsonSerializerContext, CancellationToken cancellationToken);
3434

35-
Task SendAsJsonAsync(Command command, JsonSerializerOptions jsonSerializerOptions, CancellationToken cancellationToken);
35+
Task SendAsJsonAsync(Command command, JsonSerializerContext jsonSerializerContext, CancellationToken cancellationToken);
3636
}

dotnet/src/webdriver/BiDi/Communication/Transport/WebSocketTransport.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
using System.Text.Json;
2626
using System.Text;
2727
using OpenQA.Selenium.Internal.Logging;
28+
using System.Text.Json.Serialization;
2829

2930
#nullable enable
3031

@@ -44,7 +45,7 @@ public async Task ConnectAsync(CancellationToken cancellationToken)
4445
await _webSocket.ConnectAsync(_uri, cancellationToken).ConfigureAwait(false);
4546
}
4647

47-
public async Task<T> ReceiveAsJsonAsync<T>(JsonSerializerOptions jsonSerializerOptions, CancellationToken cancellationToken)
48+
public async Task<T> ReceiveAsJsonAsync<T>(JsonSerializerContext jsonSerializerContext, CancellationToken cancellationToken)
4849
{
4950
using var ms = new MemoryStream();
5051

@@ -65,14 +66,14 @@ public async Task<T> ReceiveAsJsonAsync<T>(JsonSerializerOptions jsonSerializerO
6566
_logger.Trace($"BiDi RCV << {Encoding.UTF8.GetString(ms.ToArray())}");
6667
}
6768

68-
var res = await JsonSerializer.DeserializeAsync(ms, typeof(T), jsonSerializerOptions, cancellationToken).ConfigureAwait(false);
69+
var res = await JsonSerializer.DeserializeAsync(ms, typeof(T), jsonSerializerContext, cancellationToken).ConfigureAwait(false);
6970

7071
return (T)res!;
7172
}
7273

73-
public async Task SendAsJsonAsync(Command command, JsonSerializerOptions jsonSerializerOptions, CancellationToken cancellationToken)
74+
public async Task SendAsJsonAsync(Command command, JsonSerializerContext jsonSerializerContext, CancellationToken cancellationToken)
7475
{
75-
var buffer = JsonSerializer.SerializeToUtf8Bytes(command, typeof(Command), jsonSerializerOptions);
76+
var buffer = JsonSerializer.SerializeToUtf8Bytes(command, typeof(Command), jsonSerializerContext);
7677

7778
await _socketSendSemaphoreSlim.WaitAsync(cancellationToken);
7879

0 commit comments

Comments
 (0)