Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement a JsonConverterFactory equivalent of the existing default converter attribute #99

Merged
merged 3 commits into from
Aug 13, 2023

Conversation

jskeet
Copy link
Member

@jskeet jskeet commented Aug 6, 2023

Fixes #97.

The only test is for source generation, as that's the use case for which this is being provided.

The first commit is just renaming; the second commit is actual code.

/// with a provider of <see cref="DateTimeZoneProviders.Tzdb"/>.
/// </summary>
/// <remarks>
/// This is a factory equalivalent of <see cref="NodaTimeDefaultJsonConverterAttribute"/>.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: typo

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link
Collaborator

@malcolmr malcolmr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

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

/// <inheritdoc />
public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) =>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider renaming options to unused so that it's obvious that the parameter is being deliberately ignored?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would prefer not to do that, as it can cause confusion with named arguments. But I could fill in documentation directly instead of inheriting it, and stress that the parameter is unused?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, good point about named arguments.

I think it's okay to leave the documentation as-is: it's still correct, it's just that the options aren't relevant to any of the returned converters (I assume that is true, rather than it being a bug that we're not looking at them).

If <inheritdoc/> allows adding extra information (like {@inheritDoc} in Java), you could add a sentence here, but I'm not sure it's necessary.


/// <inheritdoc />
public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) =>
Converters.TryGetValue(typeToConvert, out var converter) ? converter : null;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps factor this out as internal static JsonConverter? GetConverter(Type), then also call it from NodaTimeDefaultJsonConverterAttribute.CreateConverter() above, and make Converters here private?

You could also implement CanConvert(type) as GetConverter(type) != null, meaning that the only access to the dictionary is via that method. (Since the converters are singletons, that's basically the same cost.) Not sure whether that's worth doing, though.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think that makes a lot of sense. Will do so.


namespace NodaTime.Serialization.Test.SystemTextJson;

public partial class NodaTimeDefaultJsonConverterFactoryTest
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps give this a more-specific name. This isn't testing NodaTimeDefaultJsonConverterFactory per se, but the use of that with source generation.

You might also link to e.g. https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/source-generation in comments here to explain what's going on?

Separately, let's add a test (which could be called NodaTimeDefaultJsonConverterFactoryTest) to assert over the factory methods directly? I know we have some coverage in NodaTimeDefaultJsonConverterAttributeTest, but it might be nice to e.g. verify that CreateConverter() for each type we care about returns a non-null instance with correct Type property, etc, and that CanConvert() is consistent with those.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've left the source generation test present in the same class (but renamed it to SourceGenerationCompatibility) and added more "normal" tests above.

@jskeet
Copy link
Member Author

jskeet commented Aug 13, 2023

@malcolmr: I've pushed another couple of commits (after rebasing); PTAL.

Copy link
Collaborator

@malcolmr malcolmr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thanks!

This refactors NodaTimeDefaultJsonConverterAttribute to use the converter dictionary which is now in NodaTimeDefaultJsonConverterFactory.

Fixes nodatime#97.
…daConverterBase.CanConvert

It looks like System.Text.Json doesn't need or expect a converter to advertise that it can handle nullable value types. (The default implementations don't do so.)

It's entirely possible that we should actually just not override the method at all here, and only do so in NodaDateTimeZoneConverter, but I don't want to change the implementation right now.
@jskeet jskeet merged commit 7dfe4db into nodatime:main Aug 13, 2023
1 check passed
@jskeet jskeet deleted the converter-factory branch August 13, 2023 17:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

System.Text.Json should expose a JsonConverterFactory for defaults
2 participants