nodatime / nodatime.serialization

Serialization projects for Noda Time

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

System.Text.Json should expose a JsonConverterFactory for defaults

Khitiara opened this issue · comments

The attribute present in the source does not work with System.Text.Json source generation, and its internal logic is easily translated to also implement a JsonConverterFactory which can more easily be used with the base JsonConverter attribute and therefore support source generation

It's not clear to me what you mean by "the attribute present in the source". I'd be happy to look at a PR to expose a factory though.

Well that hasn't been released yet, so it's not clear to me what you're proposing or what you're trying. Overall, this issue is really unclear. Please put some time into clarifying it.

I copied that source file into my project in order to use attribute-based serializer customization, but this is incompatible with the System.Text.Json source generator as elaborated further in dotnet/runtime#88638, whereas a relatively easy conversion of that type to a JsonConverterFactory restored that compatibility. My JsonConverterFactory implementation for this is attached to this issue but I do not have a nodatime.serialization dev environment set up to make a proper pull request for the change.

public sealed class NodaTimeDefaultJsonConverterFactory : JsonConverterFactory
{
    private static readonly Dictionary<Type, JsonConverter> Converters;

    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;
        }
    }

    public override bool CanConvert(Type typeToConvert) => Converters.ContainsKey(typeToConvert);

    public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options) =>
        Converters.TryGetValue(typeToConvert, out var converter) ? converter : null;
}

Okay, I'll look into this when I get a chance - but I'd be surprised if I found time for it before August.