Skip to content

Update JsonData in Experimental#32613

Merged
annelo-msft merged 24 commits intoAzure:mainfrom
annelo-msft:jsondata-experimental-updates
Dec 12, 2022
Merged

Update JsonData in Experimental#32613
annelo-msft merged 24 commits intoAzure:mainfrom
annelo-msft:jsondata-experimental-updates

Conversation

@annelo-msft
Copy link
Copy Markdown
Member

@annelo-msft annelo-msft commented Nov 22, 2022

Addresses #30717.

This PR does the following:

  • Moves JsonData into Azure.Core.Dynamic namespace
  • Removes public constructors and members from JsonData, with the exception of overloaded operators
  • Adds a ToDynamic() extension method to BinaryData, to enable response.Content.ToDynamic()
  • Returns null instead of throwing when an absent property is accessed (to mimic optional properties on Azure SDK models)
  • Enables access to indexers through dynamic interface
  • Disposes JsonDocument in calls where one is created
  • Adds a test project and tests that only have access to the JsonData public API surface
  • Adds tests for JSON object, array, leaf nodes separately

The following will be handled in a later PR:

@ghost ghost added the Azure.Core label Nov 22, 2022
@azure-sdk
Copy link
Copy Markdown
Collaborator

azure-sdk commented Nov 22, 2022

API change check

APIView has identified API level changes in this PR and created following API reviews.

Azure.Core.Experimental

@annelo-msft annelo-msft marked this pull request as ready for review December 9, 2022 21:38
@annelo-msft annelo-msft requested review from JoshLove-msft, ellismg and jsquire and removed request for JoshLove-msft December 9, 2022 21:39
@annelo-msft annelo-msft merged commit 114f309 into Azure:main Dec 12, 2022
// because apparently the type system has decided the IEnumerable
// is holding JsonData, not dynamic, so the DMO callback is never called
// and the explicit cast to int is not visible b/c JsonData is internal.
//IEnumerable value = (IEnumerable)data;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I believe this may be due to using IEnumerable which is non-generic and assumes object for the type. Does using IEnumerable<dynamic> as the cast work?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

It does not ... it fails with a RuntimeBinderException whereas just IEnumerable fails with an InvalidCastException.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

public static implicit operator float? (Azure.Core.Dynamic.JsonData json) { throw null; }
public static implicit operator float (Azure.Core.Dynamic.JsonData json) { throw null; }
public static implicit operator string (Azure.Core.Dynamic.JsonData json) { throw null; }
public static bool operator !=(Azure.Core.Dynamic.JsonData? left, int right) { throw null; }
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Don't we want equality operators for the same set of primitives that we have the casts for?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

These will be addressed in a follow-up PR. My goal was to merge this to make something available early for CloudMachine to start working with.

var json = JsonData.Parse("{}");
dynamic jsonData = json;
jsonData.a = JsonData.EmptyObject();
jsonData.a = JsonData.Parse("{}");
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If we need empty, we should somehow add specific API for it as opposed to asking users to parse {}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This is only for internal test purposes. It simulates what would be returned by a protocol method response without providing a client. Per our requirement that customers will modify JsonData instances only for round-trips, I don't think we need a formal API to create an empty instance. I can wrap the method in the test to make the intent more clear - that the caller would obtain the JsonData instance from a client method.

public void CannotGetMemberOnArray()
{
dynamic data = JsonDataTestHelpers.CreateFromJson("[1, 2, 3]");
Assert.Throws<InvalidOperationException>(() => { var x = data.Property; });
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We should think what's the right exception type to throw here.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Cool, thanks! In some places, we are also throwing JsonException, and I don't think it is currently clear when we throw which one or why.

@weshaggard
Copy link
Copy Markdown
Member

@annelo-msft looks like this change also is the reason some of the purview tests are failing see https://dev.azure.com/azure-sdk/internal/_build/results?buildId=2055180&view=logs&j=19ae9ca6-cc95-59cd-da1c-d5a57cd99bf5&t=d4ee6916-5fd3-538d-4187-7e8f2bed8e1c&l=49. It looks like it is caused by the move of JsonData to a new namespace.

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.

7 participants