Turn on the AOT analyzer. (#92)

* Turn on the AOT analyzer.

* Address feedback

* Add missing types.

* Fix build and react to conflicts.

* Fix failing test.

* Address feedback.
This commit is contained in:
Eirik Tsarpalis 2025-03-18 18:48:28 +02:00 • committed by GitHub
commit e7fa6194f6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,12 +1,17 @@
using System.Text.Json;
using McpDotNet.Protocol.Messages;
using McpDotNet.Protocol.Types;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
namespace McpDotNet.Utils.Json;
/// <summary>
/// Extensions for configuring System.Text.Json serialization options for MCP.
/// </summary>
internal static class JsonSerializerOptionsExtensions
internal static partial class JsonSerializerOptionsExtensions
{
public static JsonSerializerOptions DefaultOptions { get; } = CreateDefaultOptions();
@ -14,19 +19,54 @@ internal static class JsonSerializerOptionsExtensions
/// Creates default options to use for MCP-related serialization.
/// </summary>
/// <returns>The configured options.</returns>
[UnconditionalSuppressMessage("AotAnalysis", "IL3050", Justification = "DefaultJsonTypeInfoResolver is only used when reflection-based serialization is enabled")]
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026", Justification = "DefaultJsonTypeInfoResolver is only used when reflection-based serialization is enabled")]
private static JsonSerializerOptions CreateDefaultOptions()
{
JsonSerializerOptions options = new();
// If reflection-based serialization is enabled by default, use it, as it's the most permissive in terms of what it can serialize,
// and we want to be flexible in terms of what can be put into the various collections in the object model.
// Otherwise, use the source-generated options to enable trimming and Native AOT.
// Add custom converters
options.Converters.Add(new JsonRpcMessageConverter());
options.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase));
if (JsonSerializer.IsReflectionEnabledByDefault)
{
// Keep in sync with the JsonSourceGenerationOptions attribute on JsonContext below.
JsonSerializerOptions options = new(JsonSerializerDefaults.Web)
{
TypeInfoResolver = new DefaultJsonTypeInfoResolver(),
Converters = { new JsonStringEnumConverter() },
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
NumberHandling = JsonNumberHandling.AllowReadingFromString
};
// Configure general options
options.PropertyNameCaseInsensitive = true;
options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
options.NumberHandling = JsonNumberHandling.AllowReadingFromString;
options.MakeReadOnly();
return options;
}
return options;
return JsonContext.Default.Options;
}
internal static JsonTypeInfo<T> GetTypeInfo<T>(this JsonSerializerOptions options) =>
(JsonTypeInfo<T>)options.GetTypeInfo(typeof(T));
// Keep in sync with CreateDefaultOptions above.
[JsonSourceGenerationOptions(JsonSerializerDefaults.Web,
UseStringEnumConverter = true,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
NumberHandling = JsonNumberHandling.AllowReadingFromString)]
[JsonSerializable(typeof(JsonDocument))]
[JsonSerializable(typeof(JsonElement))]
[JsonSerializable(typeof(JsonNode))]
[JsonSerializable(typeof(IJsonRpcMessage))]
[JsonSerializable(typeof(JsonRpcRequest))]
[JsonSerializable(typeof(JsonRpcNotification))]
[JsonSerializable(typeof(JsonRpcResponse))]
[JsonSerializable(typeof(JsonRpcError))]
[JsonSerializable(typeof(ServerCapabilities))]
[JsonSerializable(typeof(Implementation))]
[JsonSerializable(typeof(CreateMessageResult))]
[JsonSerializable(typeof(ListRootsResult))]
[JsonSerializable(typeof(InitializeResult))]
[JsonSerializable(typeof(JsonSchema))]
[JsonSerializable(typeof(CallToolResponse))]
internal sealed partial class JsonContext : JsonSerializerContext;
}