-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Fixed deserialization of null arrays for issue #37606 #37616
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -2,6 +2,7 @@ | |||||||
| // The .NET Foundation licenses this file to you under the MIT license. | ||||||||
| // See the LICENSE file in the project root for more information. | ||||||||
|
|
||||||||
| using System.Collections.Generic; | ||||||||
| using Xunit; | ||||||||
|
|
||||||||
| namespace System.Text.Json.Serialization.Tests | ||||||||
|
|
@@ -17,7 +18,7 @@ public static void ClassWithNullProperty() | |||||||
|
|
||||||||
| [Fact] | ||||||||
| public static void RootObjectIsNull() | ||||||||
| { | ||||||||
| { | ||||||||
| { | ||||||||
| TestClassWithNull obj = JsonSerializer.Parse<TestClassWithNull>("null"); | ||||||||
| Assert.Null(obj); | ||||||||
|
|
@@ -27,6 +28,41 @@ public static void RootObjectIsNull() | |||||||
| object obj = JsonSerializer.Parse<object>("null"); | ||||||||
| Assert.Null(obj); | ||||||||
| } | ||||||||
|
|
||||||||
| { | ||||||||
| string obj = JsonSerializer.Parse<string>("null"); | ||||||||
| Assert.Null(obj); | ||||||||
| } | ||||||||
|
|
||||||||
| { | ||||||||
| IEnumerable<int> obj = JsonSerializer.Parse<IEnumerable<int>>("null"); | ||||||||
| Assert.Null(obj); | ||||||||
| } | ||||||||
|
|
||||||||
| { | ||||||||
| Dictionary<string, object> obj = JsonSerializer.Parse<Dictionary<string, object>>("null"); | ||||||||
| Assert.Null(obj); | ||||||||
| } | ||||||||
|
|
||||||||
| } | ||||||||
|
|
||||||||
| [Fact] | ||||||||
| public static void RootArrayIsNull() | ||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It might be good to add a test for an array within a class as well. public class Foo
{
public int[] Array {get; set;}
}
Foo obj = JsonSerializer.Parse<Foo>("{null}");
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The above test throws a
As far as testing a valid JSON object that contains a null array, it looks like that's covered by the following, which deserializes an object with various types of properties set to null (including an array):
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah yes, you are right. Good point! I meant testing with a json payload like
That isn't necessary, at least it isn't worth resetting CI over :)
|
||||||||
| { | ||||||||
| { | ||||||||
| int[] obj = JsonSerializer.Parse<int[]>("null"); | ||||||||
| Assert.Null(obj); | ||||||||
| } | ||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not used to see scope style on codebase but I could wrong @danmosemsft
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not either, but I don't think we're against it either - particularly in test code if it makes things clearer. In this case though arguably it's a "code smell" suggesting there should be 3 separate test methods.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not a huge fan of it myself, but it looked like an existing pattern in the test classes for short, repetitive tests like these.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes it's only like this in tests and is there to avoid multiple tests and prevent these sections from accidently colliding on variable names. Sometimes it's used to verify a baseline condition before testing the primary case. |
||||||||
|
|
||||||||
| { | ||||||||
| object[] obj = JsonSerializer.Parse<object[]>("null"); | ||||||||
| Assert.Null(obj); | ||||||||
| } | ||||||||
|
|
||||||||
| { | ||||||||
| TestClassWithNull[] obj = JsonSerializer.Parse<TestClassWithNull[]>("null"); | ||||||||
| Assert.Null(obj); | ||||||||
| } | ||||||||
| } | ||||||||
|
|
||||||||
| [Fact] | ||||||||
|
|
||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this code flow ultimately results in a return from
ReadCore, it should only ever be triggered at the top level (reader.CurrentDepth == 0)Second condition is to ensure that the type we're dealing with is nullable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a helper called
IsLastFrameon the stack frame that could be used instead ofCurrentDepthbut otherwise looks correct.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IsLastFramebehaves slightly different fromreader.CurrentDepth.For example, when the reader encounters
nullin the following json{ "MyProperty": null },reader.CurrentDepthis 1, butIsLastFrameistrue.IsLastFrameappears to only update when a new frame is pushed onto the stack, which happens while parsing sub-objects/sub-arrays within an object.