-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This refactors NodaTimeDefaultJsonConverterAttribute to use the converter dictionary which is now in NodaTimeDefaultJsonConverterFactory. Fixes #97.
- Loading branch information
Showing
3 changed files
with
107 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
70 changes: 70 additions & 0 deletions
70
src/NodaTime.Serialization.SystemTextJson/NodaTimeDefaultJsonConverterFactory.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
// Copyright 2023 The Noda Time Authors. All rights reserved. | ||
// Use of this source code is governed by the Apache License 2.0, | ||
// as found in the LICENSE.txt file. | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text.Json; | ||
using System.Text.Json.Serialization; | ||
|
||
namespace NodaTime.Serialization.SystemTextJson; | ||
|
||
/// <summary> | ||
/// Provides JSON default converters for Noda Time types, as if using serializer | ||
/// options configured by <see cref="Extensions.ConfigureForNodaTime(JsonSerializerOptions, IDateTimeZoneProvider)"/> | ||
/// with a provider of <see cref="DateTimeZoneProviders.Tzdb"/>. | ||
/// </summary> | ||
/// <remarks> | ||
/// This is a factory equalivalent of <see cref="NodaTimeDefaultJsonConverterAttribute"/>. | ||
/// </remarks> | ||
public sealed class NodaTimeDefaultJsonConverterFactory : JsonConverterFactory | ||
{ | ||
/// <summary> | ||
/// A dictionary of default converters, keyed by type. This includes nullable types. | ||
/// This dictionary is internal and must not be mutated after it is initialized | ||
/// in the static constructor. | ||
/// </summary> | ||
internal static Dictionary<Type, JsonConverter> Converters { get; } | ||
|
||
/// <summary> | ||
/// Constructs an instance of the factory. | ||
/// </summary> | ||
public NodaTimeDefaultJsonConverterFactory() | ||
{ | ||
} | ||
|
||
static NodaTimeDefaultJsonConverterFactory() | ||
{ | ||
Converters = new() | ||
{ | ||
{ typeof(AnnualDate), NodaConverters.AnnualDateConverter }, | ||
{ typeof(DateInterval), NodaConverters.DateIntervalConverter }, | ||
{ typeof(DateTimeZone), NodaConverters.CreateDateTimeZoneConverter(DateTimeZoneProviders.Tzdb) }, | ||
{ typeof(Duration), NodaConverters.DurationConverter }, | ||
{ typeof(Instant), NodaConverters.InstantConverter }, | ||
{ typeof(Interval), NodaConverters.IntervalConverter }, | ||
{ typeof(LocalDate), NodaConverters.LocalDateConverter }, | ||
{ typeof(LocalDateTime), NodaConverters.LocalDateTimeConverter }, | ||
{ typeof(LocalTime), NodaConverters.LocalTimeConverter }, | ||
{ typeof(Offset), NodaConverters.OffsetConverter }, | ||
{ typeof(OffsetDate), NodaConverters.OffsetDateConverter }, | ||
{ typeof(OffsetDateTime), NodaConverters.OffsetDateTimeConverter }, | ||
{ typeof(OffsetTime), NodaConverters.OffsetTimeConverter }, | ||
{ typeof(Period), NodaConverters.RoundtripPeriodConverter }, | ||
{ typeof(ZonedDateTime), NodaConverters.CreateZonedDateTimeConverter(DateTimeZoneProviders.Tzdb) } | ||
}; | ||
// Use the same converter for Nullable<T> as T. | ||
foreach (var entry in Converters.Where(pair => pair.Key.IsValueType).ToList()) | ||
{ | ||
Converters[typeof(Nullable<>).MakeGenericType(entry.Key)] = entry.Value; | ||
} | ||
} | ||
|
||
/// <inheritdoc /> | ||
public override bool CanConvert(Type typeToConvert) => Converters.ContainsKey(typeToConvert); | ||
|
||
/// <inheritdoc /> | ||
public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) => | ||
Converters.TryGetValue(typeToConvert, out var converter) ? converter : null; | ||
} |
36 changes: 36 additions & 0 deletions
36
src/NodaTime.Serialization.Test/SystemTextJson/NodaTimeDefaultJsonConverterFactoryTest.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
// Copyright 2023 The Noda Time Authors. All rights reserved. | ||
// Use of this source code is governed by the Apache License 2.0, | ||
// as found in the LICENSE.txt file. | ||
|
||
using NodaTime.Serialization.SystemTextJson; | ||
using NUnit.Framework; | ||
using System.Text; | ||
using System.Text.Json; | ||
using System.Text.Json.Serialization; | ||
|
||
namespace NodaTime.Serialization.Test.SystemTextJson; | ||
|
||
public partial class NodaTimeDefaultJsonConverterFactoryTest | ||
{ | ||
// See https://github.com/nodatime/nodatime.serialization/issues/97 | ||
[Test] | ||
public void SourceGeneration() | ||
{ | ||
var sample = new SampleData { Foo = Instant.FromUtc(2023, 8, 6, 12, 40, 12) }; | ||
byte[] utf8Json = JsonSerializer.SerializeToUtf8Bytes(sample, SampleJsonContext.Default.SampleData); | ||
string actual = Encoding.UTF8.GetString(utf8Json); | ||
string expected = "{\"Foo\":\"2023-08-06T12:40:12Z\"}"; | ||
Assert.AreEqual(expected, actual); | ||
} | ||
|
||
public class SampleData | ||
{ | ||
[JsonConverter(typeof(NodaTimeDefaultJsonConverterFactory))] | ||
public Instant Foo { get; set; } | ||
} | ||
|
||
[JsonSerializable(typeof(SampleData))] | ||
public partial class SampleJsonContext : JsonSerializerContext | ||
{ | ||
} | ||
} |