Conversation
… by using generic attributes
also return IList instead of IEnumerable everywhere for consistency
|
FYI: I will need a few days for the review. I'm pretty busy this week. |
|
I'll do the review this weekend. |
|
No worries. This currently uses a preview version of xunit aot. Stable release should be soon. |
HofmeisterAn
left a comment
There was a problem hiding this comment.
Thanks, the PR looks good! I just have a few questions so I can understand a few things better.
| } No newline at end of file | ||
| } | ||
|
|
||
| // extended types that are not generated by source generator |
There was a problem hiding this comment.
question: Do you think we can generate these? What about a separate C# generator or validation tool for the API 😬?
There was a problem hiding this comment.
I am currently not sure what the best way is to automate this.
There was a problem hiding this comment.
Yes, difficult... What do you think about a test that uses reflection to check whether the return and parameter types of the API (interface) implementations are part of the context?
There was a problem hiding this comment.
Or maybe we can write an analyser. Never done that from scratch but I can try. We need to now the generic type of MakeRequestAsync.
Not sure if a source generator would work because STJ also uses a source generator.
There was a problem hiding this comment.
We need to now the generic type of MakeRequestAsync.
Yea, that's right. My idea e.g. fails with (PluginInstallParameters vs. IList<PluginPrivilege>):
Docker.DotNet/src/Docker.DotNet/Endpoints/PluginOperations.cs
Lines 43 to 63 in 2f9b40f
Probably we need:
- MakeRequestAsync
- JsonRequestContent
- MonitorStreamForMessagesAsync
But we can also handle that in a follow-up PR if that's more convenient.
| @@ -15,11 +15,15 @@ static JsonSerializer() | |||
|
|
|||
| private JsonSerializer() | |||
There was a problem hiding this comment.
I think the following is slightly better, although the improvements compared to network I/O are probably negligible. WDYT?
Subject: [PATCH] f
---
Index: src/Docker.DotNet/JsonSerializer.cs
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/Docker.DotNet/JsonSerializer.cs b/src/Docker.DotNet/JsonSerializer.cs
--- a/src/Docker.DotNet/JsonSerializer.cs (revision e4cc73fdd8371f3dd6110684f6e7a705b55941c4)
+++ b/src/Docker.DotNet/JsonSerializer.cs (date 1776437559579)
@@ -42,26 +42,27 @@
public string Serialize<T>(T value)
{
- return System.Text.Json.JsonSerializer.Serialize(value, (JsonTypeInfo<T>)_options.GetTypeInfo(typeof(T)));
+ return System.Text.Json.JsonSerializer.Serialize(value, TypeInfoCache<T>.Value);
}
public byte[] SerializeToUtf8Bytes<T>(T value)
{
- return System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(value, (JsonTypeInfo<T>)_options.GetTypeInfo(typeof(T)));
+ return System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(value, TypeInfoCache<T>.Value);
}
public T Deserialize<T>(byte[] json)
{
- return System.Text.Json.JsonSerializer.Deserialize(json, (JsonTypeInfo<T>)_options.GetTypeInfo(typeof(T)))!;
+ return System.Text.Json.JsonSerializer.Deserialize(json, TypeInfoCache<T>.Value)!;
}
public Task<T> DeserializeAsync<T>(HttpContent content, CancellationToken cancellationToken)
{
- return content.ReadFromJsonAsync((JsonTypeInfo<T>)_options.GetTypeInfo(typeof(T)), cancellationToken)!;
+ return content.ReadFromJsonAsync(TypeInfoCache<T>.Value, cancellationToken)!;
}
public async IAsyncEnumerable<T> DeserializeAsync<T>(Stream stream, [EnumeratorCancellation] CancellationToken cancellationToken)
{
+ var typeInfo = TypeInfoCache<T>.Value;
var reader = PipeReader.Create(stream);
while (true)
@@ -73,7 +74,7 @@
while (!buffer.IsEmpty && TryParseJson(ref buffer, out var jsonDocument))
{
- yield return jsonDocument!.Deserialize((JsonTypeInfo<T>)_options.GetTypeInfo(typeof(T)))!;
+ yield return jsonDocument!.Deserialize(typeInfo)!;
}
if (result.IsCompleted)
@@ -99,6 +100,11 @@
return false;
}
+
+ private static class TypeInfoCache<T>
+ {
+ public static readonly JsonTypeInfo<T> Value = (JsonTypeInfo<T>)Instance._options.GetTypeInfo(typeof(T));
+ }
}
// Additional source-generated metadata for collections and dictionaries used by operations.
| // PluginOperations.ListPluginsAsync | ||
| [JsonSerializable(typeof(Plugin[]))] | ||
| // PluginOperations.GetPrivilegesAsync | ||
| [JsonSerializable(typeof(PluginPrivilege[]))] |
There was a problem hiding this comment.
I have one more topic, but aside from the open discussions, the PR looks good. We can also address some of those in a follow-up PR if you prefer.
PluginPrivilege[] covers the array response, but InstallPluginAsync and UpgradePluginAsync serialize an IList<PluginPrivilege>.
IList<PluginPrivilege> is a different closed type from PluginPrivilege[], so it needs its own JsonSerializable entry in the combined serializer context, right?
I belive the analyzer is a good idea 💡.
I think these are missing too (or we change them to arrays too):
// PluginOperations.InstallPluginAsync, UpgradePluginAsync
[JsonSerializable(typeof(IList<PluginPrivilege>))]
// PluginOperations.ConfigurePluginAsync
[JsonSerializable(typeof(IList<string>))]
// SecretsOperations.ListAsync
[JsonSerializable(typeof(IList<Secret>))]
// TasksOperations.ListAsync
[JsonSerializable(typeof(IList<TaskResponse>))]

IsAotCompatibleDockerModelsJsonSerializerContextwith all docker API models which have JSON parameters, so query string only models are not added for JsonSerializationDockerExtendedJsonSerializerContextwhich includes types directly used by *Operations (this can be removed / merged with DockerModelsJsonSerializerContext when STJ source generator fails when defining the serializer context in 2 partial classes dotnet/runtime#99669 is available)DynamicallyAccessedMembersattributesxunit.v3.aot.mtp-v24.0.0-pre.33which is still in preview but required to actually test AOT.xunit.v3.mtp-v24.0.0-pre.33for .NET 8.0 because xunit AOT only works from .NET 9 onwards.IEnumerableresponses to beIListfor consistency (breaking change)QueryStringParameterto reduce reflectionfixes #88