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

[dotnet] Add reflection-based JSON serialization fallback to Commands #14732

Merged
merged 2 commits into from
Nov 8, 2024

Conversation

RenderMichael
Copy link
Contributor

@RenderMichael RenderMichael commented Nov 8, 2024

User description

Fixes #14731

Thanks for contributing to Selenium!
A PR well described will help maintainers to quickly review and merge it

Before submitting your PR, please check our contributing guidelines.
Avoid large PRs, help reviewers by making them as simple and short as possible.

Description

Adds a reflection-based JSON serialization fallback, preventing unchecked exceptions from breaking scenarios.

Motivation and Context

Exceptions are being thrown for unknown types, including anonymous types.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist

  • I have read the contributing document.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have added tests to cover my changes.
  • All new and existing tests passed.

PR Type

Bug fix, Tests


Description

  • Introduced a reflection-based JSON serialization fallback in the Command class to handle unknown types, including anonymous types, preventing unchecked exceptions.
  • Enhanced JSON serialization by combining CommandJsonSerializerContext.Default with DefaultJsonTypeInfoResolver.
  • Added unit tests to verify the serialization of anonymous types within the Command class, ensuring robustness and correctness.

Changes walkthrough 📝

Relevant files
Enhancement
Command.cs
Add reflection-based JSON serialization fallback in Command class

dotnet/src/webdriver/Command.cs

  • Added JsonTypeInfoResolver.Combine to JSON serializer options.
  • Included DefaultJsonTypeInfoResolver for enhanced serialization.
  • +2/-1     
    Tests
    CommandTests.cs
    Add tests for JSON serialization of Command class               

    dotnet/test/common/CommandTests.cs

  • Added new test class CommandTests.
  • Implemented test for serializing anonymous types in commands.
  • +22/-0   

    💡 PR-Agent usage: Comment /help "your question" on any pull request to receive relevant information

    Copy link
    Contributor

    qodo-merge-pro bot commented Nov 8, 2024

    PR Reviewer Guide 🔍

    Here are some key observations to aid the review process:

    ⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
    🧪 PR contains tests
    🔒 No security concerns identified
    ⚡ Recommended focus areas for review

    Performance Impact
    The reflection-based JSON serialization fallback could impact performance compared to the previous source-generated serialization. Consider measuring and documenting any performance differences.

    Test Coverage
    The test only covers a simple anonymous type case. Consider adding more test cases with nested anonymous types, null values, and complex object structures.

    Copy link
    Contributor

    qodo-merge-pro bot commented Nov 8, 2024

    PR Code Suggestions ✨

    Explore these optional code suggestions:

    CategorySuggestion                                                                                                                                    Score
    Enhancement
    Enhance test coverage by including edge cases in serialization tests

    Add test cases for edge cases like null values and empty dictionaries to ensure
    robust serialization handling.

    dotnet/test/common/CommandTests.cs [10-16]

    -[Test]
    -public void CommandSerializesAnonymousType()
    +[TestCase(null)]
    +[TestCase(new object())]
    +public void CommandSerializesAnonymousType(object value)
     {
         var parameters = new Dictionary<string, object>
         {
    -        ["arg"] = new { param1 = true, param2 = false },
    +        ["arg"] = value,
         };
    • Apply this suggestion
    Suggestion importance[1-10]: 8

    Why: Adding test cases for null and edge cases is crucial for ensuring robust serialization behavior, significantly improving the test coverage and helping prevent potential runtime issues.

    8
    Best practice
    Improve thread safety and immutability by correctly ordering readonly and static modifiers

    Consider making the JsonSerializerOptions immutable by marking it as readonly to
    prevent accidental modifications at runtime.

    dotnet/src/webdriver/Command.cs [37]

    -private readonly static JsonSerializerOptions s_jsonSerializerOptions = new()
    +private static readonly JsonSerializerOptions s_jsonSerializerOptions = new()
    • Apply this suggestion
    Suggestion importance[1-10]: 3

    Why: While the suggestion to reorder modifiers follows C# best practices, it's a minor stylistic change that doesn't affect functionality as both forms are semantically equivalent.

    3
    Improve code style by removing unnecessary trailing comma in collection initializer

    Remove trailing comma in dictionary initialization as it's not needed and may affect
    readability.

    dotnet/test/common/CommandTests.cs [12-15]

     var parameters = new Dictionary<string, object>
     {
    -    ["arg"] = new { param1 = true, param2 = false },
    +    ["arg"] = new { param1 = true, param2 = false }
     };
    • Apply this suggestion
    Suggestion importance[1-10]: 2

    Why: The suggestion addresses a minor style preference. Trailing commas are actually beneficial in C# as they make future additions easier and produce cleaner diffs, so removing them might not be an improvement.

    2

    💡 Need additional feedback ? start a PR chat

    @nvborisenko
    Copy link
    Member

    This is very good! Nice catch!

    @RenderMichael
    Copy link
    Contributor Author

    In the short-term, this should stop all the JSON failures people may be having.

    In the long-term, this defeats some the purpose of source-generation. It's still faster, better, future-proof, etc. but it makes the AOT support "best effort". Instead, we may need separate overloads for the methods that take Dictionary<string, object> as parameters. We can expose an overload that takes a JsonNode parameter for those that want to guarantee AOT support.

    We can also add an extra parameter of JsonTypeInfo<Dictionary<string, object>> for users to provide their own type info, for the same goal.

    Either way, the Dictionary<string, object> parameters can never truly be AOT-safe

    @nvborisenko
    Copy link
    Member

    Short-term: this PR is very good for regular users (99%), for AOT let's review each particular case (if it happens).
    Long-term: "classic" commands/responses might be forwarded to BiDi implementation (strongly-typed).

    @RenderMichael
    Copy link
    Contributor Author

    AOT is music to my ears :) One day this project can have the <IsAotCompatible>true</IsAotCompatible> property and will work fully.

    I made another small PR as part of incremental progress #14733

    Copy link
    Member

    @nvborisenko nvborisenko left a comment

    Choose a reason for hiding this comment

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

    Very good drug from headache!

    @nvborisenko nvborisenko merged commit 5c9d683 into SeleniumHQ:trunk Nov 8, 2024
    10 checks passed
    @RenderMichael RenderMichael deleted the command-json branch November 9, 2024 22:40
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Projects
    None yet
    Development

    Successfully merging this pull request may close these issues.

    [🐛 Bug]: [dotnet] AOT changes have broken anonymous types
    2 participants