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

Null String being reported as String rather than JTokenType.Null #2775

Closed
robert-thorne opened this issue Dec 12, 2022 · 1 comment · Fixed by #2796
Closed

Null String being reported as String rather than JTokenType.Null #2775

robert-thorne opened this issue Dec 12, 2022 · 1 comment · Fixed by #2796

Comments

@robert-thorne
Copy link

robert-thorne commented Dec 12, 2022

Source/destination JSON

{
"NullProperty": null
}

Expected behavior

In the sample code below, we are creating a JObject with a property set by creating a null string (string nullString = null) or via a ternary operator (j_Object.Add("NullProperty", false ? "0" : null);_), in the ternary operator sometimes it is set a string value and sometimes not, we then use JToken.FromObject(jObject) to get a JToken.

We were then look at the type of the NullProperty which was a JTokenType.Null in 13.0.1.

Actual behavior

With version 13.0.1, with this code we were getting back jToken.Children().Children().Single().Type as a JTokenType.Null, but in 13.0.2 this Type returns a String type.

Looking at the of the jObject property, whose values appears to be a String in both 13.0.1 and 13.0.2, it looks like this might be a bug fix.

However, it seems if we create any other objects types other than Strings in the same way, JTokenType.Null is always returned as the property type, so wondering why a string is treated differently and hence we need to add additional null checking to our JTokens.

This is a breaking change in our code base.

Steps to reproduce

Code to test different jObject configurations

var jObject = new JObject();
jObject.Add("NullProperty", false ? "0" : null);

var jToken = JToken.FromObject(jObject);

Console.WriteLine(jToken.Children().Children().Single()); // returns JTokenType.Null in 13.0.1 and String in 13.0.2
Console.WriteLine(jObject.Children().Children().Single().Type); // returns String in 13.0.1 and String in 13.0.2

jObject = new JObject();
string nullValue = null;
jObject.Add("NullProperty", nullValue);

jToken = JToken.FromObject(jObject);

Console.WriteLine(jToken.Children().Children().Single().Type); // returns JTokenType.Null in 13.0.1 and String in 13.0.2
Console.WriteLine(jObject.Children().Children().Single().Type); // returns String in 13.0.1 and String in 13.0.2

jObject = new JObject();
jObject.Add("NullProperty", false ? 1 : null);

jToken = JToken.FromObject(jObject);

Console.WriteLine(jToken.Children().Children().Single().Type); // returns JTokenType.Null in 13.0.1 and JTokenType.Null in 13.0.2
Console.WriteLine(jObject.Children().Children().Single().Type); // returns JTokenType.Null in 13.0.1 and JTokenType.Null in 13.0.2

jObject = new JObject();
jObject.Add("NullProperty", false ? true : null);

jToken = JToken.FromObject(jObject);

Console.WriteLine(jToken.Children().Children().Single().Type); // returns JTokenType.Null in 13.0.1 and JTokenType.Null in 13.0.2
Console.WriteLine(jObject.Children().Children().Single().Type); // returns JTokenType.Null in 13.0.1 and JTokenType.Null in 13.0.2

jObject = new JObject();
jObject.Add("NullProperty", false ? JToken.FromObject(new SomeClass()) : null);

jToken = JToken.FromObject(jObject);

Console.WriteLine(jToken.Children().Children().Single().Type); // returns JTokenType.Null in 13.0.1 and JTokenType.Null in 13.0.2
Console.WriteLine(jObject.Children().Children().Single().Type); // returns JTokenType.Null in 13.0.1 and JTokenType.Null in 13.0.2

@dmmusil
Copy link
Contributor

dmmusil commented Jan 12, 2023

I had some unit tests fail with NullReferenceException during the 13.0.1 -> 13.0.2 upgrade and it ended up being this.

Trying out your code I got the differences to appear clearly in Linqpad.

image

<Query Kind="Statements">
  <NuGetReference Version="13.0.1">Newtonsoft.Json</NuGetReference>
  <Namespace>Newtonsoft.Json.Linq</Namespace>
</Query>

var jObject = new JObject();
jObject.Add("NullProperty", false ? "0" : null);

var jToken = JToken.FromObject(jObject);

Console.WriteLine(jToken.Children().Children().Single().Type); // returns JTokenType.Null in 13.0.1 and String in 13.0.2
Console.WriteLine(jObject.Children().Children().Single().Type); // returns String in 13.0.1 and String in 13.0.2

jObject = new JObject();
string nullValue = null;
jObject.Add("NullProperty", nullValue);

jToken = JToken.FromObject(jObject);

Console.WriteLine(jToken.Children().Children().Single().Type); // returns JTokenType.Null in 13.0.1 and String in 13.0.2
Console.WriteLine(jObject.Children().Children().Single().Type); // returns String in 13.0.1 and String in 13.0.2

// 13.0.1
// Null
// String
// Null
// String

<Query Kind="Statements">
  <NuGetReference>Newtonsoft.Json</NuGetReference>
  <Namespace>Newtonsoft.Json.Linq</Namespace>
</Query>

var jObject = new JObject();
jObject.Add("NullProperty", false ? "0" : null);

var jToken = JToken.FromObject(jObject);

Console.WriteLine(jToken.Children().Children().Single().Type); // returns JTokenType.Null in 13.0.1 and String in 13.0.2
Console.WriteLine(jObject.Children().Children().Single().Type); // returns String in 13.0.1 and String in 13.0.2

jObject = new JObject();
string nullValue = null;
jObject.Add("NullProperty", nullValue);

jToken = JToken.FromObject(jObject);

Console.WriteLine(jToken.Children().Children().Single().Type); // returns JTokenType.Null in 13.0.1 and String in 13.0.2
Console.WriteLine(jObject.Children().Children().Single().Type); // returns String in 13.0.1 and String in 13.0.2

// 13.0.2
// String
// String
// String
// String

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 a pull request may close this issue.

3 participants
@dmmusil @robert-thorne and others