Skip to content

Commit

Permalink
Merge pull request #2166 from erri120/fix/windowdata-serialization
Browse files Browse the repository at this point in the history
Add `Optional<T>` JSON converter
  • Loading branch information
erri120 authored Oct 14, 2024
2 parents 464830f + 65b7be3 commit 9d425b4
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 1 deletion.
69 changes: 69 additions & 0 deletions src/NexusMods.DataModel/JsonConverters/OptionalConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;
using DynamicData.Kernel;
using JetBrains.Annotations;

namespace NexusMods.DataModel.JsonConverters;

/// <summary>
/// Converter factory for <see cref="Optional{T}"/>
/// </summary>
[UsedImplicitly]
public class OptionalConverterFactory : JsonConverterFactory
{
/// <inheritdoc/>
public override bool CanConvert(Type typeToConvert)
{
if (!typeToConvert.IsGenericType) return false;
return typeToConvert.GetGenericTypeDefinition() == typeof(Optional<>);
}

/// <inheritdoc/>
public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
{
var typeArguments = typeToConvert.GetGenericArguments();
var valueType = typeArguments[0];

var converter = (JsonConverter)Activator.CreateInstance(
type: typeof(OptionalConverter<>).MakeGenericType(valueType),
bindingAttr: BindingFlags.Instance | BindingFlags.Public,
binder: null,
args: [options],
culture: null
)!;

return converter;
}

private class OptionalConverter<TValue> : JsonConverter<Optional<TValue>>
where TValue : notnull
{
private readonly JsonConverter<TValue> _valueConverter;

[UsedImplicitly]
public OptionalConverter(JsonSerializerOptions options)
{
_valueConverter = (JsonConverter<TValue>)options.GetConverter(typeof(TValue));
}

public override Optional<TValue> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.Null) return Optional<TValue>.None;
var value = _valueConverter.Read(ref reader, typeToConvert, options);
return Optional<TValue>.Create(value);
}

public override void Write(Utf8JsonWriter writer, Optional<TValue> value, JsonSerializerOptions options)
{
if (!value.HasValue)
{
writer.WriteNullValue();
}
else
{
_valueConverter.Write(writer, value.Value, options);
}
}
}
}
4 changes: 3 additions & 1 deletion src/NexusMods.DataModel/Services.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,9 @@ public static IServiceCollection AddDataModel(this IServiceCollection coll)
coll.AddSingleton<JsonConverter, GamePathConverter>();
coll.AddSingleton<JsonConverter, DateTimeConverter>();
coll.AddSingleton<JsonConverter, SizeConverter>();

coll.AddSingleton<JsonConverterFactory, OptionalConverterFactory>();
coll.AddSingleton<JsonConverter, OptionalConverterFactory>();

// Game Registry
coll.AddSingleton<IGameRegistry, GameRegistry>();
coll.AddHostedService(s => (GameRegistry)s.GetRequiredService<IGameRegistry>());
Expand Down

0 comments on commit 9d425b4

Please sign in to comment.